From 527c8e7ba7b685a1ff5a1f63e20bb7663995e14f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 27 Mar 2015 23:27:01 +0000 Subject: [PATCH] px4plus: further updates mostly to the cartridge RAM logic --- Kernel/platform-px4plus/config.h | 6 +- Kernel/platform-px4plus/devfd.c | 10 ++- Kernel/platform-px4plus/main.c | 2 + Kernel/platform-px4plus/sio.c | 7 ++ Kernel/platform-px4plus/sio.h | 2 +- Kernel/platform-px4plus/swapdev.s | 143 ++++++++++++++++++++++++++++-- 6 files changed, 158 insertions(+), 12 deletions(-) diff --git a/Kernel/platform-px4plus/config.h b/Kernel/platform-px4plus/config.h index b08190c2..d74610dc 100644 --- a/Kernel/platform-px4plus/config.h +++ b/Kernel/platform-px4plus/config.h @@ -16,7 +16,7 @@ #undef CONFIG_CPM_EMU /* Fixed banking (although we must do magic in tricks.s to fake banking */ #define CONFIG_BANK_FIXED -#define MAX_MAPS 7 +#define MAX_MAPS 7 /* also appears in kernel.def */ #define MAP_SIZE 0x8000 /* Swap only */ #undef CONFIG_SWAP_ONLY @@ -48,7 +48,7 @@ #define NUM_DEV_TTY 2 #define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ -#define SWAPDEV (256 + 0) /* Device for swapping. (ram drive) */ +#define SWAPDEV (1) /* Device for swapping. (second floppy) */ #define NBUFS 6 /* Number of block buffers */ #define NMOUNTS 2 /* Number of mounts at a time */ @@ -57,5 +57,3 @@ #define VT_RIGHT 29 #define VT_BOTTOM 7 - -#define PFTABSIZE 5 /* All we have room for right now */ diff --git a/Kernel/platform-px4plus/devfd.c b/Kernel/platform-px4plus/devfd.c index f7bd4cc6..871a7450 100644 --- a/Kernel/platform-px4plus/devfd.c +++ b/Kernel/platform-px4plus/devfd.c @@ -109,7 +109,15 @@ int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) /* We need a special I/O helper for swapping out as we may be swapping memory from an I/O mapped ram device to the floppy disc */ - read_from_bank(page, dptr, buf + 0x09, 128); + if (rawflag == 0) + memcpy(buf + 0x09, (uint8_t *)dptr, 128); + else { + romd_off = dptr; + romd_addr = (uint16_t)buf + 0x09; + romd_size = 128; + romd_mode = page; + read_from_bank(); + } sio_write(buf, 0x89); err = sio_read(buf, 0x06); if (!err) diff --git a/Kernel/platform-px4plus/main.c b/Kernel/platform-px4plus/main.c index 87ed3875..39bdbce1 100644 --- a/Kernel/platform-px4plus/main.c +++ b/Kernel/platform-px4plus/main.c @@ -28,6 +28,7 @@ void platform_interrupt(void) } extern uint8_t map_translate[MAX_MAPS]; +extern uint8_t *map_live; /* Add map numbers. These are logical mappings one of which is the current memory image and the others indexes into the sidecar or cartridge memory. @@ -58,6 +59,7 @@ void pagemap_init(void) *p++ = ct--; pagemap_add(i); } + map_live = p - 1; /* We add RAM last */ } void map_init(void) diff --git a/Kernel/platform-px4plus/sio.c b/Kernel/platform-px4plus/sio.c index 53e44a12..6505683f 100644 --- a/Kernel/platform-px4plus/sio.c +++ b/Kernel/platform-px4plus/sio.c @@ -24,6 +24,13 @@ void deselect_sio(int old) __sfr __at 0x14 artwr; __sfr __at 0x15 artsr; +/* + * FIXME: + * For these functions we need to switch to a different very fast IRQ + * handler which simply counts timer ticks, then when we finish the + * sio transfers we can run all the missed timer handling. + */ + void sio_write(uint8_t *buf, int len) { while(len--) { diff --git a/Kernel/platform-px4plus/sio.h b/Kernel/platform-px4plus/sio.h index 260f3b34..ea67ec19 100644 --- a/Kernel/platform-px4plus/sio.h +++ b/Kernel/platform-px4plus/sio.h @@ -8,6 +8,6 @@ extern void sio_write(uint8_t *buf, int len); extern int sio_read(uint8_t *buf, int len); /* These don't truely belong here but it will do for now */ -extern void read_from_bank(uint16_t bank, uint16_t dptr, uint8_t *buf, uint16_t len); +extern void read_from_bank(void); #endif \ No newline at end of file diff --git a/Kernel/platform-px4plus/swapdev.s b/Kernel/platform-px4plus/swapdev.s index de6397e4..9eb1fb20 100644 --- a/Kernel/platform-px4plus/swapdev.s +++ b/Kernel/platform-px4plus/swapdev.s @@ -1,5 +1,22 @@ ; -; Support code for swap device activity +; Support code for mmio RAM based swap devices used as if they were +; banked memory. We could have made them swap but its faster to treat +; them as memory and do switching and exchanges. It also allows us to +; avoid the cost of having an empty space as needed for swap out and +; then swap in. On a PX4 with a single 32K cartridge that is critical. +; +; The key element here is the map translation table. Each of the +; logical banks has a 1 byte entry that gives its current location +; as either +; 1 - RAM +; 2 - Cartridge, low 32K +; 3 - Cartridge, high 32K (if present) +; 0x80-0x83 - Sidecar in 32K chunks +; +; When we "switch" to a bank we actually swap the RAM contents with +; the I/O memory that held the bank we switched to, and then we fix +; up the table. That makes all the magic going on conveniently +; invisible to the core code. ; .globl _cartridge_copy @@ -11,9 +28,25 @@ .globl _map_translate .globl _map_live + .globl _read_from_bank + + .globl _romd_addr + .globl _romd_off + .globl _romd_size + .globl _romd_mode ; byte size + + .globl map_process_save + .globl map_kernel_restore + + .module swapdev + + .include "kernel.def" .area _COMMONMEM +; +; Copy the RAM into the given bank in the cartridge. This is used when +; we do a fork. ; ; A holds the bank to use (1 = RAM 2/3 for cartridge 128+ sidecar ; @@ -48,7 +81,8 @@ cart_copy256: ret ; -; Exchange the process in bank a with the process in RAM +; Exchange the process in bank a with the process in RAM. This is +; used when we do a task switch between two processes. ; _cartridge_exchange: push bc @@ -86,7 +120,10 @@ cart_x256: .area _CODE - +; +; Compute the size of a cartridge. We can only use 32K sized chunks, +; so the 16K cartridge while detected is useless. +; _cartridge_size: ld c, #0xA512 xor a @@ -114,6 +151,11 @@ size32: .area _COMMONMEM +; +; A holds the sidecar bank to use with bit 7 set. We call this +; function when we are forking a process so that we can write a copy +; of RAM into the other bank (where it will become the parent) +; _sidecar_copy: push bc push de @@ -140,6 +182,11 @@ sidecar_cnext: pop bc ret +; +; Exchange RAM and the process in sidecar bank A (with bit 7 set). +; Used when we are task switching. This is rather ugly as the +; sidecar memory helpfully auto-increments the low byte! +; _sidecar_exchange: push bc push de @@ -179,9 +226,11 @@ sidecar_xnl: ret ; -; Make the requested process the current one in memory. We use this -; on task switching but also on the floppy I/O when swapping in or -; out. Preserves DE. +; Make the requested bank the current one in memory. We use this +; when task switching. It's the PX4 logical equivalent of the out +; instructions on saner ports that switch context. It must be called +; on a private stack as it will exchange the kernel/irq stacks of the +; old and new task as it runs. ; _make_mapped: ld c, a @@ -212,3 +261,85 @@ in_sidecar: in_memory2: pop de ; recover task pointer ret + +; +; We have to deal with the awkward case of I/O wanting to access other +; banks for swapping. On a normal setup this is fairly trivial, in our +; case the memory they want to copy may in fact be stuffed into an I/O +; mapped device so we need to do some gymnastics. +; +_read_from_bank: ; (page, dptr, buf) always 128 bytes + ld de, (_romd_mode) + ld d, #0 + ld hl, #_map_translate + add hl, de + ld a, (hl) ; Translation entry + cp #1 + jr z, memory_read ; It is in RAM + ; + ; Turn virtual address into offset in swap in HL as both + ; other methods need this + ; + ld hl, (_romd_off) ; in bytes, userspace ptr + ld de, #SWAP_VTOP + or a + sbc hl, de ; convert to zero based + bit 7, a ; cartridge is 2/3 + jr z, cartridge_read + ; + ; Pull it from the sidecar (0x80-0x83) + ; + ld b, #0 + rra ; effectively multiply by 32768 + rr b ; 0x0 or 0x80 + and #0x3f ; 32K per process + out (0x92), a ; select right 64K bank + ; + ; Now work out which 256 byte page is needed + ; + ld a, h + add b ; 32K low bit of bank number + out (0x91), a ; middle byte of I/O offset + ld a, l + out (0x90), a ; low byte of I/O offset + ld bc, #0x8093 ; 128 count, port 92) + ld hl, (_romd_addr) + inir ; 128 bytes into hl + ret +; +; 2 is the low 32K, 3 the high +; +cartridge_read: + cp #2 + jr z, cart_read_1 + set 7,h ; offset by another 32K +cart_read_1: + ld a, h + out (0x10), a ; set high byte + ld de, (_romd_addr) + ld b, #0x80 ; 128 bytes +cart_read_l: + ld a, l ; sufficient as this won't + out (0x11), a ; cross a page + in a, (0x12) + ld (de), a + inc de + inc l + djnz cart_read_l + ret +; +; Pull 128 bytes from user space. We pull a trick here. +; We are copying between user space and kernel writable data. +; Only R/O space is banked on the PX4 systems so we don't need +; to play bank pogo. +; +memory_read: + ld bc, #0x80 + ld de, (_romd_addr) + call map_process_save + ldir + call map_kernel_restore + ret + +_map_translate: .ds MAX_MAPS +_map_live: .dw 0 -- 2.34.1