From 152aaae0503b8e6de616788d097b165193ab0295 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Sun, 3 Nov 2024 21:23:13 -0800 Subject: [PATCH 1/2] [kernel] Split XMS/DMA buffer from track cache for BIOS and DF drivers --- elks/arch/i86/drivers/block/bioshd.c | 31 +++++++++++---------- elks/arch/i86/drivers/block/directfd.c | 6 ++-- elks/include/linuxmt/config.h | 38 +++++++++++++++++--------- emu86.sh | 12 ++++---- 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/elks/arch/i86/drivers/block/bioshd.c b/elks/arch/i86/drivers/block/bioshd.c index 21954cf28..9f15c0e58 100644 --- a/elks/arch/i86/drivers/block/bioshd.c +++ b/elks/arch/i86/drivers/block/bioshd.c @@ -106,7 +106,7 @@ static struct gendisk bioshd_gendisk = { static void BFPROC set_cache_invalid(void) { - if (cache_drive) debug_cache2("INV%d ", cache_drive - drive_info); + if (cache_drive) debug_cache("INV%d ", bios_drive_map[cache_drive - drive_info]); cache_drive = NULL; } @@ -525,11 +525,11 @@ static void BFPROC get_chst(struct drive_infot *drivep, sector_t *start_sec, #if FULL_TRACK if (fulltrack) { int save = *s; - int max_sectors = DMASEGSZ / drivep->sector_size; + int max_sectors = TRACKSEGSZ / drivep->sector_size; if (*s - 1 < max_sectors) { /* adjust start sector backwards for full track read*/ *s = 1; *t = max_sectors; - } else { /* likely 2880k: limit to size of DMASEG buffer */ + } else { /* likely 2880k: limit to size of TRACKSEG buffer */ *s = max_sectors + 1; *t = drivep->sectors - *s + 1; } @@ -559,8 +559,6 @@ static int BFPROC do_readwrite(struct drive_infot *drivep, sector_t start, char if (cmd == READ) debug_bios("bioshd(%x): read lba %ld count %d\n", drive, start, this_pass); - errs = MAX_ERRS; /* BIOS disk reads should be retried at least five times */ - do { #pragma GCC diagnostic ignored "-Wshift-count-overflow" usedmaseg = seg >> 16; /* will be nonzero only if XMS configured and XMS buffer */ if (!usedmaseg) { @@ -576,13 +574,16 @@ static int BFPROC do_readwrite(struct drive_infot *drivep, sector_t start, char offset = 0; if (cmd == WRITE) /* copy xms buffer down before write*/ xms_fmemcpyw(0, DMASEG, buf, seg, this_pass*(drivep->sector_size >> 1)); - set_cache_invalid(); + //set_cache_invalid(); /* don't invalidate cache - not shared */ } else { segment = (seg_t)seg; offset = (unsigned) buf; } - debug_cache("%s%d CHS %d/%d/%d count %d\n", - cmd==WRITE? "WR": "RD", drive, cylinder, head, sector, this_pass); + errs = MAX_ERRS; /* BIOS disk reads should be retried at least five times */ + do { + debug_cache("%s%s%d CHS %d/%d/%d count %d\n", + cmd==WRITE? "WR": "RD", usedmaseg? "X": "", drive, cylinder, head, sector, + this_pass); debug_bios("bioshd(%x): cmd %d CHS %d/%d/%d count %d\n", drive, cmd, cylinder, head, sector, this_pass); @@ -602,8 +603,10 @@ static int BFPROC do_readwrite(struct drive_infot *drivep, sector_t start, char if (usedmaseg) { if (cmd == READ) /* copy DMASEG up to xms*/ xms_fmemcpyw(buf, seg, 0, DMASEG, this_pass*(drivep->sector_size >> 1)); - set_cache_invalid(); + //set_cache_invalid(); /* don't invalidate cache - not shared */ } + if (cmd == WRITE && drivep == cache_drive) + set_cache_invalid(); /* cache isn't updated on writes */ return this_pass; } @@ -611,7 +614,7 @@ static int BFPROC do_readwrite(struct drive_infot *drivep, sector_t start, char static sector_t cache_startsector; static sector_t cache_endsector; -/* read from start sector to end of track into DMASEG track buffer, no retries*/ +/* read from start sector to end of track into TRACKSEG track buffer, no retries*/ static void BFPROC do_readtrack(struct drive_infot *drivep, sector_t start) { unsigned int cylinder, head, sector, num_sectors; @@ -621,8 +624,8 @@ static void BFPROC do_readtrack(struct drive_infot *drivep, sector_t start) drive = bios_drive_map[drive]; get_chst(drivep, &start, &cylinder, &head, §or, &num_sectors, 1); - if (num_sectors > (DMASEGSZ / drivep->sector_size)) - num_sectors = DMASEGSZ / drivep->sector_size; + if (num_sectors > (TRACKSEGSZ / drivep->sector_size)) + num_sectors = TRACKSEGSZ / drivep->sector_size; do { debug_cache("\nTR%d %lu(CHS %u,%u,%u-%u) ", drive, start>>1, cylinder, head, @@ -632,7 +635,7 @@ static void BFPROC do_readtrack(struct drive_infot *drivep, sector_t start) bios_set_ddpt(drivep->sectors); error = bios_disk_rw(BIOSHD_READ, num_sectors, drive, - cylinder, head, sector, DMASEG, 0); + cylinder, head, sector, TRACKSEG, 0); if (error) { printk("bioshd(%x): track read retry #%d CHS %d/%d/%d count %d\n", drive, errs + 1, cylinder, head, sector, num_sectors); @@ -665,7 +668,7 @@ static int BFPROC cache_valid(struct drive_infot *drivep, sector_t start, char * offset = (int)(start - cache_startsector) * drivep->sector_size; debug_bios("bioshd(%x): cache hit lba %ld\n", bios_drive_map[drivep-drive_info], start); - xms_fmemcpyw(buf, seg, (void *)offset, DMASEG, drivep->sector_size >> 1); + xms_fmemcpyw(buf, seg, (void *)offset, TRACKSEG, drivep->sector_size >> 1); return 1; } diff --git a/elks/arch/i86/drivers/block/directfd.c b/elks/arch/i86/drivers/block/directfd.c index 8d2a6d788..4fb22cb0b 100644 --- a/elks/arch/i86/drivers/block/directfd.c +++ b/elks/arch/i86/drivers/block/directfd.c @@ -137,10 +137,10 @@ char USE_IMPLIED_SEEK = 0; /* =1 for QEMU with 360k/AT stretch floppies (not rea #define TIMEOUT_CMD_COMPL (6 * HZ) /* 6 secs wait for FDC command complete */ /* locations for cache and bounce buffers */ -#define CACHE_SEG DMASEG /* track cache at DMASEG:0 (shared with BIOS driver) */ -#define CACHE_OFF 0 -#define BOUNCE_SEG DMASEG /* share bounce buffer with track cache at DMASEG:0 */ +#define BOUNCE_SEG TRACKSEG /* share bounce buffer with track cache at TRACKSEG:0 */ #define BOUNCE_OFF 0 +#define CACHE_SEG TRACKSEG /* track cache at TRACKSEG:0 (same as BIOS FD driver) */ +#define CACHE_OFF 0 #define FLOPPY_DMA 2 /* hardwired on old PCs */ diff --git a/elks/include/linuxmt/config.h b/elks/include/linuxmt/config.h index 94fa4e3c9..085c5574e 100644 --- a/elks/include/linuxmt/config.h +++ b/elks/include/linuxmt/config.h @@ -103,27 +103,39 @@ #define DEF_SETUPSEG DEF_INITSEG + 0x20 #define DEF_SYSMAX 0x2F00 /* maximum system size (=.text+.fartext+.data) */ -/* Segment DMASEG up to DMASEGEND is used as a bounce buffer of at least 1K (=BLOCKSIZE) - * below the first 64K boundary (=0x1000:0) for use with the old 8237 DMA controller. - * If floppy track caching is enabled, this area is also used for the track buffer - * for direct DMA access using multisector I/O. - * Following DMASEGEND is the kernel code and data at REL_SYSSEG. +/* Segment DMASEG up to DMASEGEND is used for the XMS/DMA bounce buffer and track cache. + * Following DMASEGEND is the kernel code at REL_SYSSEG (or kernel data for ROM configs). + * + * A "bounce buffer" is configured below the first 64K boundary for use with + * old 8237 DMA controller which wraps addresses wider than 16-bits on PC/XT systems. + * If floppy track caching is enabled, the track buffer is also configured in + * low memory for direct DMA access usig multisector I/O. + * The DF driver uses the first sector of its track cache for the XMS/DMA buffer. + * In contrast, the BIOS FD/HD driver is configured to use an XMS/DMA buffer + * outside its track cache; thus the complicated defines below. */ +#if defined(CONFIG_BLK_DEV_BFD) || defined(CONFIG_BLK_DEV_BHD) +#define DMASEGSZ 0x0400 /* BLOCK_SIZE (1024) for external XMS/DMA buffer */ +#else +#define DMASEGSZ 0 /* no external XMS/DMA buffer */ +#endif + +#if defined(CONFIG_BLK_DEV_BFD) || defined(CONFIG_BLK_DEV_BHD) || defined(CONFIG_BLK_FD) #ifdef CONFIG_TRACK_CACHE /* floppy track buffer in low mem */ -#define DMASEGSZ 0x2400 /* SECTOR_SIZE * 18 (9216) */ +#define TRACKSEGSZ 0x2400 /* SECTOR_SIZE * 18 (9216) */ #else -#define DMASEGSZ 0x0400 /* BLOCK_SIZE (1024) */ +#define TRACKSEGSZ 0x0400 /* BLOCK_SIZE (1024) */ +#endif +#define TRACKSEG (DMASEG+(DMASEGSZ>>4)) +#define DMASEGEND (DMASEG+(DMASEGSZ>>4)+(TRACKSEGSZ>>4)) +#else +#define DMASEGEND DMASEG /* no DMASEG buffer */ #endif -#define DMASEGEND (DMASEG+(DMASEGSZ>>4)) #ifdef CONFIG_ROMCODE -#if defined(CONFIG_BLK_DEV_BFD) || defined(CONFIG_BLK_DEV_BHD) /* BIOS disk driver*/ -#define DMASEG 0x80 /* 0x400 bytes floppy sector buffer */ +#define DMASEG 0x80 /* start of floppy sector buffer */ #define KERNEL_DATA DMASEGEND /* kernel data segment */ -#else -#define KERNEL_DATA 0x080 /* kernel data segment */ -#endif #define SETUP_DATA CONFIG_ROM_SETUP_DATA #endif diff --git a/emu86.sh b/emu86.sh index 5a3b66b87..1baf26d1a 100755 --- a/emu86.sh +++ b/emu86.sh @@ -12,20 +12,18 @@ # Kernel image @ segment 0xE000 (as 64K BIOS extension) # Root filesystem @ segment 0x8000 (assumes 512K RAM & 512K ROM) -# 8088 version using emu-rom-full.config from './buildimages.sh fast' +# 8088 ROM version using emu-rom-full.config from './buildimages.sh fast' exec emu86 -w 0xe0000 -f image/rom-8088.bin -w 0x80000 -f image/romfs-8088.bin ${1+"$@"} -# just built rom version using 'make' -exec emu86 -w 0xe0000 -f elks/arch/i86/boot/Image -w 0x80000 -f image/romfs.bin ${1+"$@"} +# just built ROM version using 'make' +#exec emu86 -w 0xe0000 -f elks/arch/i86/boot/Image -w 0x80000 -f image/romfs.bin ${1+"$@"} # For ELKS Full ROM Configuration: # ELKS must be configured minimally with 'cp emu86-rom-full.config .config' # This adds MINIX/FAT filesytems with BIOS driver - -exec emu86 -w 0xe0000 -f elks/arch/i86/boot/Image -w 0x80000 -f image/romfs.bin -I image/fd1440.bin ${1+"$@"} +#exec emu86 -w 0xe0000 -f rom-8088.bin -w 0x80000 -f image/romfs.bin -I image/fd1440.img ${1+"$@"} # For ELKS disk image Configuration: # ELKS must be configured with 'cp emu86-disk.config .config' # This uses headless console, HLT on idle, no CONFIG_IDE_PROBE - -exec emu86 -I image/fd1440.bin ${1+"$@"} +#exec emu86 -I image/fd1440.img ${1+"$@"} From 9222e05d77699e2cb869e7e7af09dd25b6d19c2f Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Mon, 4 Nov 2024 16:11:50 -0800 Subject: [PATCH 2/2] Don't invalidate cache on writes unless operating on current cached drive Set TRACKSEGSZ 0 unless CONFIG_TRACK_CACHE or DF Indentation cleanup --- elks/arch/i86/drivers/block/bioshd.c | 45 ++++++++++++++-------------- elks/include/linuxmt/config.h | 10 +++++-- emu86.sh | 2 +- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/elks/arch/i86/drivers/block/bioshd.c b/elks/arch/i86/drivers/block/bioshd.c index 9f15c0e58..558ce2034 100644 --- a/elks/arch/i86/drivers/block/bioshd.c +++ b/elks/arch/i86/drivers/block/bioshd.c @@ -560,25 +560,25 @@ static int BFPROC do_readwrite(struct drive_infot *drivep, sector_t start, char drive, start, this_pass); #pragma GCC diagnostic ignored "-Wshift-count-overflow" - usedmaseg = seg >> 16; /* will be nonzero only if XMS configured and XMS buffer */ - if (!usedmaseg) { - /* check for 64k I/O overlap */ - physaddr = (seg << 4) + (unsigned int)buf; - end = this_pass * drivep->sector_size - 1; - usedmaseg = (physaddr + end < physaddr); - debug_blk("bioshd: %p:%p = %p count %d wrap %d\n", - (unsigned int)seg, buf, physaddr, this_pass, usedmaseg); - } - if (usedmaseg) { - segment = DMASEG; /* if xms buffer use DMASEG*/ - offset = 0; - if (cmd == WRITE) /* copy xms buffer down before write*/ - xms_fmemcpyw(0, DMASEG, buf, seg, this_pass*(drivep->sector_size >> 1)); - //set_cache_invalid(); /* don't invalidate cache - not shared */ - } else { - segment = (seg_t)seg; - offset = (unsigned) buf; - } + usedmaseg = seg >> 16; /* will be nonzero only if XMS configured and XMS buffer */ + if (!usedmaseg) { + /* check for 64k I/O overlap */ + physaddr = (seg << 4) + (unsigned int)buf; + end = this_pass * drivep->sector_size - 1; + usedmaseg = (physaddr + end < physaddr); + debug_blk("bioshd: %p:%p = %p count %d wrap %d\n", + (unsigned int)seg, buf, physaddr, this_pass, usedmaseg); + } + if (usedmaseg) { + segment = DMASEG; /* if xms buffer use DMASEG*/ + offset = 0; + if (cmd == WRITE) /* copy xms buffer down before write*/ + xms_fmemcpyw(0, DMASEG, buf, seg, this_pass*(drivep->sector_size >> 1)); + //set_cache_invalid(); /* don't invalidate cache - not shared */ + } else { + segment = (seg_t)seg; + offset = (unsigned) buf; + } errs = MAX_ERRS; /* BIOS disk reads should be retried at least five times */ do { debug_cache("%s%s%d CHS %d/%d/%d count %d\n", @@ -598,6 +598,9 @@ static int BFPROC do_readwrite(struct drive_infot *drivep, sector_t start, char } while (error && --errs); /* On error, retry up to MAX_ERRS times */ last_drive = drivep; + if (cmd == WRITE && drivep == cache_drive) + set_cache_invalid(); /* cache not updated on write so invalidate */ + if (error) return 0; /* error message in blk.h */ if (usedmaseg) { @@ -605,8 +608,6 @@ static int BFPROC do_readwrite(struct drive_infot *drivep, sector_t start, char xms_fmemcpyw(buf, seg, 0, DMASEG, this_pass*(drivep->sector_size >> 1)); //set_cache_invalid(); /* don't invalidate cache - not shared */ } - if (cmd == WRITE && drivep == cache_drive) - set_cache_invalid(); /* cache isn't updated on writes */ return this_pass; } @@ -689,8 +690,8 @@ static int BFPROC do_cache_read(struct drive_infot *drivep, sector_t start, char do_readtrack(drivep, start); /* read whole track*/ if (cache_valid(drivep, start, buf, seg)) /* try cache again*/ return 1; + //set_cache_invalid(); /* old code invalidated cache on failure */ } - set_cache_invalid(); return 0; } #endif diff --git a/elks/include/linuxmt/config.h b/elks/include/linuxmt/config.h index 085c5574e..dbbe6fa23 100644 --- a/elks/include/linuxmt/config.h +++ b/elks/include/linuxmt/config.h @@ -115,7 +115,7 @@ * outside its track cache; thus the complicated defines below. */ -#if defined(CONFIG_BLK_DEV_BFD) || defined(CONFIG_BLK_DEV_BHD) +#if defined(CONFIG_BLK_DEV_BFD) || defined(CONFIG_BLK_DEV_BHD) /* BIOS driver */ #define DMASEGSZ 0x0400 /* BLOCK_SIZE (1024) for external XMS/DMA buffer */ #else #define DMASEGSZ 0 /* no external XMS/DMA buffer */ @@ -123,9 +123,13 @@ #if defined(CONFIG_BLK_DEV_BFD) || defined(CONFIG_BLK_DEV_BHD) || defined(CONFIG_BLK_FD) #ifdef CONFIG_TRACK_CACHE /* floppy track buffer in low mem */ -#define TRACKSEGSZ 0x2400 /* SECTOR_SIZE * 18 (9216) */ +# define TRACKSEGSZ 0x2400 /* SECTOR_SIZE * 18 (9216) */ #else -#define TRACKSEGSZ 0x0400 /* BLOCK_SIZE (1024) */ +# ifdef CONFIG_BLK_FD +# define TRACKSEGSZ 0x0400 /* DF driver requires DMASEG internal to TRACKSEG */ +# else +# define TRACKSEGSZ 0 /* no TRACKSEG buffer */ +# endif #endif #define TRACKSEG (DMASEG+(DMASEGSZ>>4)) #define DMASEGEND (DMASEG+(DMASEGSZ>>4)+(TRACKSEGSZ>>4)) diff --git a/emu86.sh b/emu86.sh index 1baf26d1a..9c89c9970 100755 --- a/emu86.sh +++ b/emu86.sh @@ -21,7 +21,7 @@ exec emu86 -w 0xe0000 -f image/rom-8088.bin -w 0x80000 -f image/romfs-8088.bin $ # For ELKS Full ROM Configuration: # ELKS must be configured minimally with 'cp emu86-rom-full.config .config' # This adds MINIX/FAT filesytems with BIOS driver -#exec emu86 -w 0xe0000 -f rom-8088.bin -w 0x80000 -f image/romfs.bin -I image/fd1440.img ${1+"$@"} +#exec emu86 -w 0xe0000 -f image/rom-8088.bin -w 0x80000 -f image/romfs-8088.bin -I image/fd1440.img ${1+"$@"} # For ELKS disk image Configuration: # ELKS must be configured with 'cp emu86-disk.config .config'