From 601fadea0bfc7cf2d5d120e078857ae51dac83e4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 11 Apr 2018 23:37:52 +0100 Subject: [PATCH] pcw8256: add initial cut at hard disk drivers Update some notes Add some of the swap bits (more is needed see the COCO3) --- Kernel/platform-pcw8256/Makefile | 18 ++- Kernel/platform-pcw8256/README | 41 ++++++- Kernel/platform-pcw8256/config.h | 5 +- Kernel/platform-pcw8256/devfhd.c | 97 +++++++++++++++ Kernel/platform-pcw8256/devfhd.h | 28 +++++ Kernel/platform-pcw8256/devices.c | 12 +- Kernel/platform-pcw8256/fidhd.c | 162 +++++++++++++++++++++++++ Kernel/platform-pcw8256/fuzix.lnk | 7 ++ Kernel/platform-pcw8256/pcw8256.s | 6 + Kernel/platform-pcw8256/platform_ide.h | 6 + 10 files changed, 375 insertions(+), 7 deletions(-) create mode 100644 Kernel/platform-pcw8256/devfhd.c create mode 100644 Kernel/platform-pcw8256/devfhd.h create mode 100644 Kernel/platform-pcw8256/fidhd.c create mode 100644 Kernel/platform-pcw8256/platform_ide.h diff --git a/Kernel/platform-pcw8256/Makefile b/Kernel/platform-pcw8256/Makefile index 164a0d53..bb5ea2dd 100644 --- a/Kernel/platform-pcw8256/Makefile +++ b/Kernel/platform-pcw8256/Makefile @@ -1,13 +1,21 @@ -CSRCS = devlpr.c devtty.c devfd.c +CSRCS = devlpr.c devtty.c devfd.c devfhd.c fidhd.c CSRCS += devices.c main.c +DSRCS = ../dev/devide.c ../dev/blkdev.c ../dev/mbr.c +DISCARD_DSRCS = ../dev/devide_discard.c + +CROSS_CCOPTS += -I ../dev/ + ASRCS = crt0.s commonmem.s pcw8256.s ASRCS += tricks.s fdc765.s COBJS = $(CSRCS:.c=.rel) AOBJS = $(ASRCS:.s=.rel) -OBJS = $(COBJS) $(AOBJS) +DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS)) +DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS)) + +OBJS = $(COBJS) $(AOBJS) $(DOBJS) $(DISCARD_DOBJS) JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst) @@ -19,6 +27,12 @@ $(COBJS): %.rel: %.c $(AOBJS): %.rel: %.s $(CROSS_AS) $(ASOPTS) $< +$(DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DISCARD_DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + clean: rm -f $(OBJS) $(JUNK) core *~ diff --git a/Kernel/platform-pcw8256/README b/Kernel/platform-pcw8256/README index 1c3019ac..61c57e8e 100644 --- a/Kernel/platform-pcw8256/README +++ b/Kernel/platform-pcw8256/README @@ -52,8 +52,47 @@ At that point the keyboard should work. The floppy driver is incomplete but given a rootfs image on /dev/fd1 you should be able to at least get it to mount -device 0 = fd0 1 = fd1 +device 256 = fd0 257 = fd1 + +(0-255 are the UIDE hard disks, or FID hard disks on Joyce) Mixed boot/root images are not currently supported (this just needs a modified boot block that starts at a different offset) + + +Memory +------ + +Then PCW8256 memory is split into multiple banks not all of which can be used +for any purpose + +The display takes 23040 bytes of video line memory. Each line must be within +the low 128K and is indexed by the roller RAM + +The roller RAM must also be within the low 128K and is 512 bytes. + +The keyboard magically replaces the top 16 bytes of bank 3. + +Our loader puts the screen into bank 4 and bank 5 (part of), then loads the +OS into bank 0/1/2/3. We really need to rearrange this so we set the +final kernel map as something like + +0 1 3 5 (4 is display in map) + +except that means we must field a hole between BFF0 (keyboard) and Cxxx ( +display). We then end up with a map of + +0000-0087 Boot loader +0088-BFEF Kernel image +BFF0-BFFF Keyboard +C000-D9FF Video (lower window) +DA00-DBFF Roller map +DC00-E3FF Font +E400-... Video +... -FFFF Common + +Whilst doing video we map over 8000-BFFF and rely upon the video and common +mappings + +That leaves bank 2, 6+ for userspace (kernel + video costs us 80K) diff --git a/Kernel/platform-pcw8256/config.h b/Kernel/platform-pcw8256/config.h index 57f06e0b..96f812c8 100644 --- a/Kernel/platform-pcw8256/config.h +++ b/Kernel/platform-pcw8256/config.h @@ -31,6 +31,9 @@ #define VT_RIGHT 89 #define VT_BOTTOM 31 +#define MAX_BLKDEV 1 /* UIDE or FIDHD never both */ +#define CONFIG_IDE /* Has an IDE controller - maybe anyway: UIDE */ + #define TICKSPERSEC 50 /* Ticks per second */ #define PROGBASE 0x0000 /* memory base of program */ #define PROGLOAD 0x0100 /* load base of program */ @@ -55,6 +58,6 @@ #define NMOUNTS 2 /* Number of mounts at a time */ -#define swap_map(x) ((uint8_t *)(x)) /* For now */ +#define swap_map(x) (uint8_t *)(0x4000 + ((x) & 0x3FFF)) /* For now */ #define platform_discard() diff --git a/Kernel/platform-pcw8256/devfhd.c b/Kernel/platform-pcw8256/devfhd.c new file mode 100644 index 00000000..e286e856 --- /dev/null +++ b/Kernel/platform-pcw8256/devfhd.c @@ -0,0 +1,97 @@ +/* + * An implementation of the FID based hard disk interface for Joyce. + * Currently only hard disk interfaces are handled by this driver. + */ +#include +#include +#include +#include +#include + +#define MAX_FHD 16 + +static const char *errstr[2] = { "write", "read" }; +static uint8_t drivemask; +static uint8_t drivebase; +static struct dpb dpb[MAX_FHD]; + +static uint8_t devfhd_transfer_sector(void) +{ + uint8_t err; + uint8_t drive = blk_op.blkdev->driver_data; + fhd_drive = drivebase + drive; + fhd_dpb = dpb + drive; + /* For now assume HD fixed geometry */ + fhd_track = blk_op.lba >> 5; + fhd_sector = blk_op.lba & 0x1F; + fhd_op = blk_op.is_read ? 4 : 5; + err = rw_fidhd(); + if (err) { + kprintf("fhd%c: %s error %d\n", 'a' + drive, errstr[blk_op.is_read], err); + return 0; + } + return 1; +} + +static int devfhd_flush_cache(void) +{ + uint8_t err; + uint8_t drive = blk_op.blkdev->driver_data; + fhd_drive = drivebase + drive; + fhd_dpb = dpb + drive; + err = flush_fidhd(); + if (err) { + kprintf("fhd%c: flush error %d\n", 'a' + drive, err); + udata.u_error = EIO; + return -1; + } + return 0; +} + +/* FIXME These bits could be discard.. */ + +int devfhd_init(void) +{ + blkdev_t *blk; + uint8_t d; + + /* Either not supported or too old */ + if (probe_fidhd() < 2) + return 0; + fhd_op = 4; + fhd_drive = 0; + fhd_dpb = dpb; + /* Find first slot to install */ + fhd_drive = drivebase = install_fidhd(); + if (fhd_drive == 0xFF) + return 0; + /* Now begin registering */ + fhd_op = 0; + for (d = 0; d < MAX_FHD; d++) { + uint8_t next = install_fidhd(); + if (next != 0xFF) + drivemask |= (1 << d); + /* The current driver guarantees us a 1:1 so we don't do a lookup + table. Maybe we should for the future and use next as intended */ + fhd_drive++; + fhd_dpb++; + } + fhd_dpb = dpb; + fhd_drive = drivebase; + for (d = 0; d + drivebase < MAX_FHD; d++) { + if (drivemask & (1 << d)) { + login_fidhd(); + blk = blkdev_alloc(); + if (!blk) + break; + blk->transfer = devfhd_transfer_sector; + blk->flush = devfhd_flush_cache; + blk->driver_data = d; + blk->drive_lba_count = 16834; /* FIXME use dpb */ + blkdev_scan(blk, SWAPSCAN); /* Won't damage fhd_dpb/drive */ + } + fhd_drive++; + fhd_dpb++; + } + return drivemask; +} diff --git a/Kernel/platform-pcw8256/devfhd.h b/Kernel/platform-pcw8256/devfhd.h new file mode 100644 index 00000000..190ac9e5 --- /dev/null +++ b/Kernel/platform-pcw8256/devfhd.h @@ -0,0 +1,28 @@ +struct dpb { + uint16_t spt; + uint8_t bsh; + uint8_t blm; + uint8_t exm; + uint16_t dsm; + uint16_t drm; + uint8_t al0; + uint8_t al1; + uint16_t cks; + uint16_t off; + uint8_t psh; + uint8_t phm; +}; + +extern int devfhd_init(void); + +extern uint8_t fhd_drive; +extern uint8_t fhd_op; +extern uint16_t fhd_track; +extern uint16_t fhd_sector; +extern struct dpb *fhd_dpb; + +extern uint8_t probe_fidhd(void); +extern uint8_t install_fidhd(void); +extern uint8_t login_fidhd(void); +extern uint8_t flush_fidhd(void); +extern uint8_t rw_fidhd(void); diff --git a/Kernel/platform-pcw8256/devices.c b/Kernel/platform-pcw8256/devices.c index 07dacde4..ad2c45d9 100644 --- a/Kernel/platform-pcw8256/devices.c +++ b/Kernel/platform-pcw8256/devices.c @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -12,10 +15,10 @@ struct devsw dev_tab[] = /* The device driver switch table */ { // minor open close read write ioctl // ----------------------------------------------------------------- - /* 0: /dev/fd Floppy disc block devices */ + /* 0: /dev/hd Hard disc block devices (UIDE or FIDHD) */ + { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl }, /* 0: /dev/hd -- standard block device interface */ + /* 1: /dev/fd Floppy disc block devices */ { fd_open, no_close, fd_read, fd_write, no_ioctl }, - /* 1: /dev/hd Hard disc block devices (absent) */ - { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, /* 2: /dev/tty TTY devices */ { tty_open, tty_close, tty_read, tty_write, vt_ioctl }, /* 3: /dev/lpr Printer devices */ @@ -39,4 +42,7 @@ void device_init(void) { tty_init_port(); fd_probe(); + /* See what we are attaching */ + if (devfhd_init() == 0) + devide_init(); } diff --git a/Kernel/platform-pcw8256/fidhd.c b/Kernel/platform-pcw8256/fidhd.c new file mode 100644 index 00000000..45a884b2 --- /dev/null +++ b/Kernel/platform-pcw8256/fidhd.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include + +char spambuf[93]; +struct dpb *fhd_dpb; +uint8_t fhd_drive; +uint8_t fhd_op; /* must follow fhd_drive directly */ +uint16_t fhd_sector; +uint16_t fhd_track; + +uint8_t probe_fidhd(void) __naked +{ +__asm + xor a + .db 0xed + .db 0xfe + ld l,a + or a + ret z + ld l,h + ret +__endasm; +} + +/* + * Install a drive using the given dpb, with spambuf as a buffer + * for (currrntly) unused messages on error [93 byte] + * + * Caller sets driveno, returns volume number to use or FF on fail + */ + +uint8_t install_fidhd(void) __naked +{ +__asm + push ix + push iy + ld bc,#0x00fe ; probably FF for MYZ80 only ? + ld ix, (_fhd_dpb) + ld hl, #_spambuf + ld de, (_fhd_drive) ; d = op e = drive + ld a,#7 + .db 0xed + .db 0xfe + cp #2 + ld l,#0xFF + jr nz, instbad + ld l,b +instbad: + pop iy + pop ix + ret +__endasm; +} + +/* + * Returns 0 for ok, 1/2/FF on error as others + */ +uint8_t flush_fidhd(void) __naked +{ +__asm + push ix + push iy + ld ix, (_fhd_dpb) + ld a, (_fhd_drive) + ld b,a + ld a,#6 + .byte 0xed + .byte 0xfe + pop iy + pop ix + ld h,#0 + ld l,a + ret z + ret c + ld h,b + ret +__endasm; +} +/* + * Returns 0 for OK and if ok also writes the 17 byte DPB for this + * drive to ix. In theory the DPB we get handed back could be for a + * whole tonload of formats but the main one we care about is the myz80 + * 8MB image with 16k/track (32 sectors), 512 tracks. + * + * Currently we must do the login at boot time and we can't tolerate + * a media change of size. (see read/write case for why). + */ +uint8_t login_fidhd(void) __naked +{ +__asm + push ix + push iy + ld bc, (_fhd_drive-1) + ld ix, (_fhd_dpb) + ld a, #3 + .byte 0xed + .byte 0xfe + pop iy + pop ix + ld h,#0 + ld l,a + ret +__endasm; +} + +COMMON_MEMORY + +/* + * Low level I/O has to live in common as we switch banks around in + * order to read into user space or into a paging bank. + * + * Warning: because our common is copied per instance our variables + * in common are map specific. + * + * Read a sector. On return 0 = ok, 1 = error FF = mediach + * if recoverable error high byte = error code else 0 + */ + +uint8_t rw_fidhd(void) __naked +{ +__asm + ld a,(_fhd_op) + push ix + push iy + ; We must fetch these while in kernel bank. dataptr will point into + ; the bank we switch to but the dpb is in kernel bank. + ; + ; We rely upon the fact we scan all the drives before userspace + ; runs thus the dpb has been copied into each common copy and is + ; static. + ; + ld ix, (_fhd_dpb) + ld iy, (_blk_op+BLKPARAM_ADDR_OFFSET) + ld de, (_fhd_sector) + ld hl, (_fhd_track) + ld bc, (_fhd_drive-1) + push af + ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) + or a + jr z, k_map + cp #1 + call z, map_process_always + ld a, (_blk_op+BLKPARAM_SWAP_PAGE) + call nz, map_for_swap +k_map: + pop af + .byte 0xed + .byte 0xfe + pop iy + pop ix + call map_kernel + ld h,#0 + ld l,a + ret z + ret c + ld h,b + ret +__endasm; +} diff --git a/Kernel/platform-pcw8256/fuzix.lnk b/Kernel/platform-pcw8256/fuzix.lnk index d47043da..ea74c7bd 100644 --- a/Kernel/platform-pcw8256/fuzix.lnk +++ b/Kernel/platform-pcw8256/fuzix.lnk @@ -38,4 +38,11 @@ platform-pcw8256/devlpr.rel platform-pcw8256/devtty.rel vt.rel font8x8.rel +platform-pcw8256/blkdev.rel +platform-pcw8256/mbr.rel +platform-pcw8256/devide.rel +platform-pcw8256/devide_discard.rel +platform-pcw8256/devfhd.rel +platform-pcw8256/fidhd.rel + -e diff --git a/Kernel/platform-pcw8256/pcw8256.s b/Kernel/platform-pcw8256/pcw8256.s index ce876259..6eb91791 100644 --- a/Kernel/platform-pcw8256/pcw8256.s +++ b/Kernel/platform-pcw8256/pcw8256.s @@ -14,6 +14,7 @@ .globl _need_resched .globl map_save .globl map_restore + .globl map_for_swap .globl platform_interrupt_all .globl _copy_common @@ -179,6 +180,11 @@ map_kernel: pop af ret +map_for_swap: + ld (map_current+1),a + out (0xF1),a ; map at 0x4000 + ret + map_process_always: push af push hl diff --git a/Kernel/platform-pcw8256/platform_ide.h b/Kernel/platform-pcw8256/platform_ide.h new file mode 100644 index 00000000..2b8824d4 --- /dev/null +++ b/Kernel/platform-pcw8256/platform_ide.h @@ -0,0 +1,6 @@ +#define ide_select(x) +#define ide_deselect() + +/* UIDE8 for the PCW series: 8bit, no altstatus/control */ +#define IDE_8BIT_ONLY +#define IDE_REG_CS1_BASE 0xC8 -- 2.34.1