From a49380ac4f1ce05d3d9440cc70e4bac6c897a753 Mon Sep 17 00:00:00 2001
From: Timothy E Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
Date: Sun, 3 Nov 2013 11:57:38 +0000
Subject: [PATCH 29/35] Kernel Miscellaneous changes to RISC OS kernel for
 Linux, including mmap based dynamic areas.

Conflicts:
	castle/RiscOS/Sources/Kernel/s/HAL
---
 castle/RiscOS/Sources/Kernel/Makefile     |   8 +
 castle/RiscOS/Sources/Kernel/c/LinuxC     | 252 +++++++++++++++++++++++++++++-
 castle/RiscOS/Sources/Kernel/hdr/Kernel   |   5 +-
 castle/RiscOS/Sources/Kernel/hdr/KernelWS |  53 +++++--
 castle/RiscOS/Sources/Kernel/hdr/Options  |  10 +-
 castle/RiscOS/Sources/Kernel/hdr/PublicWS |  10 +-
 castle/RiscOS/Sources/Kernel/s/ArthurSWIs |   2 +
 castle/RiscOS/Sources/Kernel/s/ChangeDyn  | 105 ++++++++++++-
 castle/RiscOS/Sources/Kernel/s/GenHeader  |  79 ++++++++++
 castle/RiscOS/Sources/Kernel/s/GetAll     |   4 +
 castle/RiscOS/Sources/Kernel/s/HAL        |  68 +++++++-
 castle/RiscOS/Sources/Kernel/s/Kernel     |  10 +-
 castle/RiscOS/Sources/Kernel/s/Linux      | 172 ++++++++++++++++++++
 castle/RiscOS/Sources/Kernel/s/MemInfo    |  29 +++-
 castle/RiscOS/Sources/Kernel/s/Middle     |  41 ++++-
 castle/RiscOS/Sources/Kernel/s/NewIRQs    |  10 ++
 castle/RiscOS/Sources/Kernel/s/NewReset   |  12 ++
 castle/RiscOS/Sources/Kernel/s/PMF/key    |   2 +
 castle/RiscOS/Sources/Kernel/s/PMF/osinit |   2 +
 castle/RiscOS/Sources/Kernel/s/SWINaming  |   1 +
 castle/RiscOS/Sources/Kernel/s/Utility    |   2 +
 21 files changed, 825 insertions(+), 52 deletions(-)
 create mode 100644 castle/RiscOS/Sources/Kernel/s/GenHeader
 create mode 100644 castle/RiscOS/Sources/Kernel/s/Linux

diff --git a/castle/RiscOS/Sources/Kernel/Makefile b/castle/RiscOS/Sources/Kernel/Makefile
index a6e472b..643f9d1 100644
--- a/castle/RiscOS/Sources/Kernel/Makefile
+++ b/castle/RiscOS/Sources/Kernel/Makefile
@@ -156,6 +156,14 @@ s.TMOSHelp: ${TOKENS} HelpStrs
         ${TOKENISE} ${TOKENS} HelpStrs $@
 
 o.GetAll: s.TMOSHelp
+o.LinuxC: h.Kernel
+
+#
+# Internal C header
+#
+h.Kernel: o.GenHeader
+        ${LD} -bin -o $@ o.GenHeader
+        SetType $@ FFF
 
 #
 # Exported interface headers
diff --git a/castle/RiscOS/Sources/Kernel/c/LinuxC b/castle/RiscOS/Sources/Kernel/c/LinuxC
index 206284e..49464af 100644
--- a/castle/RiscOS/Sources/Kernel/c/LinuxC
+++ b/castle/RiscOS/Sources/Kernel/c/LinuxC
@@ -16,5 +16,255 @@
  * online at www.castle-technology.co.uk/riscosbaselicence.htm
  */
 
-void dummy_function(void) {
+#include <syscalls.h>
+#include <linux/mman.h>
+#include <linux/fcntl.h>
+#include "Kernel.h"
+
+struct DANode {
+  struct DANode *Link;    // points to next node
+  uint32_t Number;        // number of this area
+  char    *Base;          // base address of area (points in middle of doubly-mapped areas)
+  uint32_t Flags;         // various flags
+  uint32_t Size;          // current size of area (not counting holes, if Sparse area)
+  uint32_t MaxSize;       // maximum size of area
+  uint32_t Workspace;     // workspace pointer when calling handlers
+  void (*Handler)();      // pointer to handler routine for area
+  uint32_t Title;         // pointer to area title
+  uint32_t SubLink;       // next node in any disjoint sublist (currently used for Shrinkables only)
+  uint32_t SparseHWM;     // high water mark, if Sparse area (highest base+size claimed for area)
+  struct DANode *SortLink;// next node in alphabetically sorted list
+  int File;
+};
+
+extern void CheckAppSpace(void);
+
+#define MY_PROT (PROT_READ | PROT_WRITE | PROT_EXEC)
+#define MY_MAP (MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED)
+
+static int TempFile(void) {
+  // FIXME use random filename
+  int fd = sys_open("/tmp/RISC OS", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL | O_NOFOLLOW, 0700);
+  if (fd >= 0) {
+    sys_unlink("/tmp/RISC OS");
+  } else {
+    sys_MESSAGE(2, "Unable to create temporary file!\n");
+  }
+  return fd;
+}
+
+struct result {
+  uint32_t error;
+  int amount;
+};
+
+#define CALL_HANDLER(...)           \
+        MOV     r2, pages;          \
+        MOV     r3, amount;         \
+        MOV     r4, da->Size;       \
+        MOV     r5, Page_Size;      \
+        MOV     r12, da->Workspace; \
+        BLX     da->Handler, {r0, r2, r3, r4, r5, r12}, {__VA_ARGS__}
+
+__value_in_regs struct result doMoveMemory(uint32_t number, int amount, struct DANode *da1) {
+  struct result result;
+  struct DANode *da = da1;
+
+  result.error = 0;
+
+  if (da1 == &FreePoolDANode) {
+    da = &AppSpaceDANode;
+    amount = -amount;
+
+    // Check if the app approves
+    __asm {
+        MOV     r0, number
+        MOV     r10, amount
+        BL      CheckAppSpace, {r0, r10}, {r0, psr}
+        MOVVS   result.error, r0
+        BVS     error
+    }
+  }
+
+  // Doubly mapped areas must be file backed, so make it so.
+  if ((da->Flags & (DynAreaFlags_DoublyMapped | DynAreaFlags_FileBacked)) == DynAreaFlags_DoublyMapped) {
+
+    //Open tempoary file.
+    int fd = TempFile();
+    if (fd < 0) goto error;
+
+    // And store it.
+    da->File = fd;
+    da->Flags |= DynAreaFlags_FileBacked;
+  }
+
+  if (amount > 0) {
+
+    // Clamp amount to maxinum area size.
+    if (amount > da->MaxSize - da->Size) amount = da->MaxSize - da->Size;
+
+    // Call the handler
+    int pages = amount / Page_Size;
+    if (da->Handler) {
+      __asm {
+        MOV     r0, #0
+        CALL_HANDLER(r0, psr)
+        MOVVS   result.error, r0
+        BVS     error
+      }
+    }
+
+    // Work out new area size.
+    uint32_t newSize = da->Size + amount;
+
+    // Is it backed by a Linux file?
+    if (da->Flags & DynAreaFlags_FileBacked) {
+
+      // Grow the file.
+      if (sys_ftruncate(da->File, newSize)) goto error;
+
+      // Extend the mapping.
+      if (sys_mmap(da->Base + da->Size, amount, MY_PROT, MAP_SHARED | MAP_FIXED, da->File, da->Size) != da->Base + da->Size) goto error;
+
+      // Is it doublely mapped?
+      if (da->Flags & DynAreaFlags_DoublyMapped) {
+
+        // If so move and extend bottom mapping.
+        if (sys_mmap(da->Base - newSize, newSize, MY_PROT, MAP_SHARED | MAP_FIXED, da->File, 0) != da->Base - newSize) goto error;
+      }
+
+    } else {
+
+      // Extend the mapping.
+      if (sys_mmap(da->Base + da->Size, amount, MY_PROT, MY_MAP, -1, 0) != da->Base + da->Size) goto error;
+    }
+
+    // Store new size
+    da->Size = newSize;
+
+    // Reentry permitted.
+    CDASemaphore = 0;
+
+    // Call the handler
+    if (da->Handler) __asm {
+        MOV     r0, #1
+        CALL_HANDLER(psr)
+    }
+
+  } else {
+
+    // Make amount positive.
+    amount = -amount;
+
+    // Clamp amount to area size.
+    if (amount > da->Size) amount = da->Size;
+
+    // Out if nothing  to move.
+    if (amount == 0) goto error;
+
+    // Call the handler
+    if (da->Handler) {
+      int pages = amount / Page_Size;
+      __asm {
+        MOV     r0, #2
+        CALL_HANDLER(r0, r3, psr)
+        MOV     amount, r3
+        MOVVS   result.error, r0
+        BVS     error
+      }
+    }
+
+    // Page align amount again.
+    amount = (amount + (Page_Size - 1)) & ~(Page_Size - 1);
+
+    // Out if nothing to move.
+    if (amount <= 0) goto error;
+
+    uint32_t newSize = da->Size - amount;
+
+    // Is it doublely mapped?
+    if (da->Flags & DynAreaFlags_DoublyMapped) {
+
+      // Move the bottom mapping up
+      if (sys_mmap(da->Base - newSize, newSize, MY_PROT, MAP_SHARED | MAP_FIXED, da->File, 0) != da->Base - newSize) goto error;
+
+      // Remove the start of the bottom mapping.
+      sys_mmap(da->Base - da->Size, amount, PROT_NONE, MY_MAP | MAP_NORESERVE, -1, 0);
+    }
+
+    // remove the end of the area
+    sys_mmap(da->Base + newSize, amount, PROT_NONE, MY_MAP | MAP_NORESERVE, -1, 0);
+
+    // Store new size
+    da->Size = newSize;
+
+    // Reentry permitted.
+    CDASemaphore = 0;
+
+    // Truncate file
+    if (da->Flags & DynAreaFlags_FileBacked) sys_ftruncate(da->File, newSize);
+
+
+    // Call the handler
+    int pages = amount / Page_Size;
+    if (da->Handler) __asm {
+        MOV     r0, #4
+        CALL_HANDLER(psr)
+    }
+
+    // Renegate the amount for Service_MemoryMoved
+    amount = -amount;
+
+  }
+
+  if (da1 == &FreePoolDANode) amount = -amount;
+  result.amount = amount;
+  return result;
+
+error:
+  CDASemaphore = 0;
+  result.amount = 0;
+  return result;
+}
+
+void Init_MapInRAM2(void* addr, unsigned permissions, unsigned length) {
+  sys_MESSAGE(2, "Init_MapInRAM2\n");
+
+  int map = MAP_PRIVATE | MAP_ANONYMOUS;
+  int prot = MY_PROT;
+
+  // Specify MAP_FIXED when mapping in page zero, otherwise it is interpreted as anywhere.
+  if (addr < (void *)0x8000) map |= MAP_FIXED;
+
+  // Or are just reserving address space.
+  if (!permissions) {
+    map |= MAP_NORESERVE;
+    prot = PROT_NONE;
+  }
+
+  if (sys_mmap(addr, length, prot, map, -1, 0) != addr) {
+    sys_MESSAGE(2, "Memory mapping failed.\n");
+    sys_exit(3);
+  }
+}
+
+static void do_IMB_part(void *start, void *end, char *start2, uint32_t size2) {
+  if (start2 > start) start = start2;
+  if ((start2 + size2) < end) end = start2 + size2;
+  if (start < end) sys_cacheflush(start, end, 0);
+}
+
+void do_IMB(unsigned unused1, void *start, void *end) {
+  do_IMB_part(start, end, (void *)ZeroPage, 0x4000);
+  do_IMB_part(start, end, (void *)ScratchSpace, ScratchSpaceSize);
+  do_IMB_part(start, end, (void *)0x8000, AplWorkSize);
+
+  struct DANode* i = DAList;
+  while(i) {
+    do_IMB_part(start, end, i->Base, i->Size);
+    i = i->Link;
+  }
+}
+
+void AMBControl_Init(void) {
 }
diff --git a/castle/RiscOS/Sources/Kernel/hdr/Kernel b/castle/RiscOS/Sources/Kernel/hdr/Kernel
index 20b261b..3c4c335 100644
--- a/castle/RiscOS/Sources/Kernel/hdr/Kernel
+++ b/castle/RiscOS/Sources/Kernel/hdr/Kernel
@@ -255,7 +255,10 @@ MinAplWork * 40*1024         ; minimum size of AplWork
 
 MEMCADR  * &03600000
         GBLL    ROMatTop
- [ HAL32 :LAND: {TRUE}
+ [ Machine = "Linux"
+ROM      * &30400000 ; Avoid Linux and QEMU
+ROMLimit * ROM  + OSROM_ImageSize * 1024
+ ELIF HAL32 :LAND: {TRUE}
 ROM      * &FC000000
 ROMatTop SETL {TRUE}
  |
diff --git a/castle/RiscOS/Sources/Kernel/hdr/KernelWS b/castle/RiscOS/Sources/Kernel/hdr/KernelWS
index 35e9d0b..c0922a7 100644
--- a/castle/RiscOS/Sources/Kernel/hdr/KernelWS
+++ b/castle/RiscOS/Sources/Kernel/hdr/KernelWS
@@ -229,6 +229,9 @@ DANode_Title      #     4               ; pointer to area title
 DANode_SubLink    #     4               ; next node in any disjoint sublist (currently used for Shrinkables only)
 DANode_SparseHWM  #     4               ; high water mark, if Sparse area (highest base+size claimed for area)
 DANode_SortLink   #     4               ; next node in alphabetically sorted list
+ [ MEMM_Type = "Linux"
+DANode_File       #     4               ; Linux file descriptor of area
+ ]
 DANode_NodeSize   #     0
 
 ; Bits in dynamic area flags (and page flags)
@@ -246,17 +249,31 @@ DynAreaFlags_Shrinkable         *  1 :SHL:  9   ; whether area may be shrunk whe
 DynAreaFlags_SparseMap          *  1 :SHL: 10   ; whether area may have non-contiguous mapping of pages (Holey dynamic areas Batman!)
 DynAreaFlags_PiersBinding       *  1 :SHL: 11   ; whether area is bound to client application, and so may be swapped out with it (not implemented yet)
 DynAreaFlags_CPBits             *  7 :SHL: 12   ; cache policy variant for NotBufferable and NotCacheable bits
+ [ MEMM_Type = "Linux"
+DynAreaFlags_FileBacked         *  1 :SHL: 16   ; whether area is backed by a file
+ ]
 
 
 ; The addresses below are only temporary; eventually most of them will be allocated at run time (we hope!)
 
  [ HiProcVecs
+   [ Machine = "Linux"
+ZeroPage            * &307F0000
+   |
 ZeroPage            * &FFFF0000
+   ]
  |
 ZeroPage            * &00000000
  ]
 
  [ HAL
+
+   [ Machine = "Linux"
+KernelWSBase        * &30800000
+   |
+KernelWSBase        * &FA000000
+   ]
+
 ; Sort out 26/32 bit versions
 SVCStackSize        *  32*1024
 IRQStackSize        *   8*1024
@@ -271,27 +288,29 @@ RMAAddress          * AplWorkMaxSize ; temporary - run time allocate?
 RMAMaxSize          * &10000000 ; 256M
 FreePoolAddress     * RMAAddress + RMAMaxSize
 
+   [ PagedMemory
 IOLimit             * &BA000000 ; initial lower limit on room for IO space (DA creation may move limit up)
 IO                  * &FA000000 ; works downwards
-HALWorkspace        * &FA000000
+   ]
+HALWorkspace        * &00000000 + KernelWSBase
 HALWorkspaceSize    * &00100000
-IRQStackAddress     * &FA100000
-SVCStackAddress     * &FA200000
-ABTStackAddress     * &FA300000
-UNDStackAddress     * &FA400000
-PhysicalAccess      * &FAE00000
-DCacheCleanAddress  * &FAF00000 ; eg. for StrongARM, 256k of space, up to FAF40000
-KbuffsBaseAddress   * &FAF40000 ; kernel buffers for long command lines, size KbuffsMaxSize
-HALWorkspaceNCNB    * &FAFE8000 ; 32K of uncacheable HAL workspace (if requested)
-CursorChunkAddress  * &FAFF0000
-DuffEntry           * &FAFF8000 ; No page ever mapped in here (L2PT entry always 0), also, all non mapped pages
-Nowhere             * DuffEntry ; use this as their CAM entry. There is only one 'Nowhere' (synonym).
-L2PT                * &FB000000
-L1PT                * &FB400000
-SysHeapChunkAddress * &FB404000
+IRQStackAddress     * &00100000 + KernelWSBase
+SVCStackAddress     * &00200000 + KernelWSBase
+ABTStackAddress     * &00300000 + KernelWSBase
+UNDStackAddress     * &00400000 + KernelWSBase
+PhysicalAccess      * &00E00000 + KernelWSBase
+DCacheCleanAddress  * &00F00000 + KernelWSBase ; eg. for StrongARM, 256k of space, up to FAF40000
+KbuffsBaseAddress   * &00F40000 + KernelWSBase ; kernel buffers for long command lines, size KbuffsMaxSize
+HALWorkspaceNCNB    * &00FE8000 + KernelWSBase ; 32K of uncacheable HAL workspace (if requested)
+CursorChunkAddress  * &00FF0000 + KernelWSBase
+DuffEntry           * &00FF8000 + KernelWSBase ; No page ever mapped in here (L2PT entry always 0), also, all non mapped pages
+Nowhere             * DuffEntry                ; use this as their CAM entry. There is only one 'Nowhere' (synonym).
+L2PT                * &01000000 + KernelWSBase
+L1PT                * &01400000 + KernelWSBase
+SysHeapChunkAddress * &01404000 + KernelWSBase
 SysHeapAddress      * SysHeapChunkAddress
-SysHeapMaxSize      * &FB800000 - SysHeapAddress
-CAM                 * &FB800000
+SysHeapMaxSize      * &01800000 + KernelWSBase - SysHeapAddress
+CAM                 * &01800000 + KernelWSBase
 CAMspace            * 8*1024*1024 ; enough for 4GB of RAM
 
 IRQSTK              * IRQStackAddress + IRQStackSize
diff --git a/castle/RiscOS/Sources/Kernel/hdr/Options b/castle/RiscOS/Sources/Kernel/hdr/Options
index 9229d4a..e25d4c2 100644
--- a/castle/RiscOS/Sources/Kernel/hdr/Options
+++ b/castle/RiscOS/Sources/Kernel/hdr/Options
@@ -172,7 +172,7 @@ LateAborts      SETL    {TRUE}
 ShrinkableDAs   SETL    {TRUE}
 
                 GBLL    DA_Batman               ; Holey dynamic areas Batman!
-DA_Batman       SETL    {TRUE}                  ; concept of sparsely mapped dynamic areas introduced for Ursula
+DA_Batman       SETL    Machine != "Linux"      ; FIXME ; concept of sparsely mapped dynamic areas introduced for Ursula
 
                 GBLL    ShadowROM               ; if true, the ROM is mirrored above
 ShadowROM       SETL    {FALSE}                 ; &FF800000
@@ -214,7 +214,7 @@ StrongARM_POST     SETL {TRUE}  :LAND: StrongARM
 
 ARM6support        SETL (MEMM_Type = "ARM600")  ; Needs updating for VMSAv6 compatability
 XScaleMiniCache    SETL {FALSE}
-XScaleJTAGDebug    SETL {TRUE}
+XScaleJTAGDebug    SETL Machine != "Linux" ; FIXME - what about IOMD?
 ECC                SETL {FALSE}
 
                 ;mjs
@@ -238,7 +238,7 @@ ChocolateOSMod         SETL {TRUE}
 ChocolateSysVars       SETL {TRUE}
 ChocolateOscli         SETL {TRUE}
 ChocolateService       SETL {TRUE}
-ChocolateAMB           SETL {TRUE} :LAND: No26bitCode   ; not implemented for 26bit kernel at present
+ChocolateAMB           SETL PagedMemory :LAND: No26bitCode   ; not implemented for 26bit kernel at present
   [ ChocolateSysHeap
                        GBLA  MaxChocolateCBBlocks  ;max quick CallBack blocks available at any one time (else ordinary heap nodes used)
                        GBLA  MaxChocolateSVBlocks  ;max quick Software Vector blocks available at any one time (else ordinary heap nodes used)
@@ -288,7 +288,7 @@ DebugHALTX      SETL    (Version :AND: 1) = 1   ; Yes for odd numbered developme
 DebugROMPostInit SETL   (:LNOT: ChocolateService) :LAND: {FALSE}
 
                 GBLL    DebugTerminal           ; default WRCH and RDCH through HAL
-DebugTerminal   SETL    {FALSE}
+DebugTerminal   SETL    Machine == "Linux"
 
                 GBLL    InverseTextTransparency
 InverseTextTransparency SETL    {FALSE}
@@ -316,7 +316,7 @@ FixCallBacks    SETL    {TRUE}                  ; also addresses some atomicity
 InterlacedPointer SETL {TRUE} :LAND: STB        ; enable code to do proper interlaced pointer
 
                 GBLL    HiProcVecs              ; Relocate processor vectors and first 16K of workspace to &FFFF0000
-HiProcVecs      SETL    {FALSE} ; Leave off for now
+HiProcVecs      SETL    Machine = "Linux" ; Leave off for now, except for Linux
 ; In an ideal world, we'd use something like this:
 ; HiProcVecs      SETL    "$Machine"="Tungsten" :LOR: :LNOT: NoARMv6
 
diff --git a/castle/RiscOS/Sources/Kernel/hdr/PublicWS b/castle/RiscOS/Sources/Kernel/hdr/PublicWS
index f2e4888..0201a95 100644
--- a/castle/RiscOS/Sources/Kernel/hdr/PublicWS
+++ b/castle/RiscOS/Sources/Kernel/hdr/PublicWS
@@ -168,10 +168,12 @@ Legacy_BgEcfOraEor         #      4*16    ; Interleaved zgora & zgeor (from Vdu
                     ^ &00004000
 ScratchSpace        #     &4000
 
- [ {FALSE}
-                    ^ &01F04000
- |
-                    ^ &FAFF4000
+ [ :DEF: Machine
+  [ Machine = "Linux"
+                    ^ &317F4000
+  |
+                    ^ &FAFF4000 ; Was &01F04000
+  ]
  ]
 SoundWorkSpace      #     &2000
 
diff --git a/castle/RiscOS/Sources/Kernel/s/ArthurSWIs b/castle/RiscOS/Sources/Kernel/s/ArthurSWIs
index 4dd5ab2..2adadae 100644
--- a/castle/RiscOS/Sources/Kernel/s/ArthurSWIs
+++ b/castle/RiscOS/Sources/Kernel/s/ArthurSWIs
@@ -816,10 +816,12 @@ Issue_Service ROUT             ; R1 is service number, R2 may be a parameter
        Push    "R9-R12, lr"
 
 ;do the direct calls to AMBControl for service calls of interest
+ [ PagedMemory
        CMP      R1, #Service_MemoryMoved
        BLEQ     AMBsrv_memorymoved
        CMP      R1, #Service_PagesSafe
        BLEQ     AMBsrv_pagessafe
+ ]
 
        CMP      R1, #Service_ClaimFIQ
        CMPNE    R1, #Service_ClaimFIQinBackground
diff --git a/castle/RiscOS/Sources/Kernel/s/ChangeDyn b/castle/RiscOS/Sources/Kernel/s/ChangeDyn
index 4ed03fa..5c09382 100644
--- a/castle/RiscOS/Sources/Kernel/s/ChangeDyn
+++ b/castle/RiscOS/Sources/Kernel/s/ChangeDyn
@@ -290,6 +290,7 @@ CDS_PostService
         MakeErrorBlock ChDynamNotAllMoved
 
 
+ [ PagedMemory
 ; in:   r0 = logical address where page is now
 
 GetPageFlagsForR0IntoR6 Entry "R0-R2, R4-R5, R7"
@@ -469,6 +470,7 @@ CheckCacheabilityR0ByMinusR2 ROUT
         SUB     r0, r0, r2
         EXIT
   ]
+ ] ; PagedMemory
 
 ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ; In    r0 bits 0..6 = area number
@@ -561,6 +563,7 @@ ReadMemMapInfo_Code
       MOV      R1, R1, LSR R11
       ExitSWIHandler
 
+ [ PagedMemory
 ; ************************************************************************
 ; SWI ReadMemMapEntries: R0 pointer to list.
 ;  Entries are three words long, the first of which is the CAM page number.
@@ -732,6 +735,7 @@ SetMemMapEntries_Code  ROUT
 02
         Pull    "r0-r6, r9, lr"
         ExitSWIHandler
+ ] ; PagedMemory
 
         LTORG
 
@@ -1023,8 +1027,10 @@ DAC_roundup
         BL      AllocateAreaAddress             ; in: r4 = flags, r5 = size of area needed; out: r3, or V=1, r0->error
         BVS     %BT25
 40
+ [ PagedMemory
         BL      AllocateBackingLevel2           ; in: r3 = address, r4 = flags, r5 = size; out: VS if error
         BVS     %BT25
+ ] ; PagedMemory
 
         Push    "r0,r1,r3"
   [ DynArea_QuickHandles
@@ -1038,7 +1044,7 @@ DAC_roundup
         BL      ClaimSysHeapNode                ; out: r2 -> node
         STRVS   r0, [sp]
         Pull    "r0,r1,r3"
-        BVS     %BT25                           ; failed to claim node
+        BVS     %BT25                           ; failed to claim node - FIXME free address space on Linux
 
 ; now store data in node (could probably use STM if we shuffled things around)
 
@@ -1369,6 +1375,22 @@ DAR_notsparse
         Pull    "r0-r2"
 
 DAR_delink
+ [ MEMM_Type = "Linux"
+        Push    "r0-r2, r7"
+        LDR     r2, [r10, #DANode_Flags]
+        LDR     r0, [r10, #DANode_Base]
+        LDR     r1, [r10, #DANode_MaxSize]
+        TST     r2, #DynAreaFlags_DoublyMapped
+        SUBNE   r0, r0, r1
+        MOVNE   r1, r1, lsl #2
+        LDR     r7, =__NR_munmap
+        SWI     0xC0000
+        TST     r2, #DynAreaFlags_FileBacked
+        LDRNE   r0, [r10, #DANode_File]
+        LDRNE   r7, =__NR_close
+        SWINE   0xc0000
+        Pull    "r0-r2, r7"
+ ] ; Linux
 
   [ DynArea_QuickHandles
 ;
@@ -2235,7 +2257,11 @@ QCheckAreaNumber ROUT
 ;       endif
 ;
 
+ [ MEMM_Type = "Linux"
+CheckForOverlappingAreas Entry "r0-r7"
+ |
 CheckForOverlappingAreas Entry "r0-r5"
+ ]
         TST     r4, #DynAreaFlags_DoublyMapped          ; check if doubly mapped
         BEQ     %FT05                                   ; [not, so don't mangle]
 
@@ -2244,6 +2270,26 @@ CheckForOverlappingAreas Entry "r0-r5"
         MOVS    r5, r5, LSL #1                          ; and double size
         BCS     %FT20                                   ; if that wrapped then that's bad, too
 05
+ [ MEMM_Type = "Linux"
+        MOV     r6, r3
+        MOV     r0, r3
+        MOV     r1, r5
+        MOV     r2, #PROT_NONE
+        MOV     r3, #MAP_PRIVATE | MAP_ANONYMOUS
+        ORR     r3, r3, #MAP_NORESERVE
+        MOV     r4, #0
+        MOV     r5, #0
+        LDR     r7, =__NR_mmap2
+        SWI     0xC0000
+        CMP     r0, #0xFFFFFF00
+        BHI     %FT20                                   ; Error number returned so failure
+        MOV     r3, r6
+        TEQ     r3, r0                                  ; Check if allocated address space is as requested
+        BEQ     %FT50                                   ; OK, so exit
+        LDR     r7, =__NR_munmap                        ; If not, free the allocated address space.
+        SWI     0xC0000
+ | ; Linux
+
         ADDS    r5, r5, r3                              ; r5 -> end +1
         BHI     %FT20                                   ; if CS, indicating wrap, and not EQ (ie just ending at 0), then bad
 
@@ -2266,7 +2312,7 @@ CheckForOverlappingAreas Entry "r0-r5"
         BLS     %FT30
         CMP     r3, r1                                  ; if start of our area is >= end of fixed, then go onto next area
         BCS     %BT10
-
+ ] ; Linux
 20
         ADRL    r0, ErrorBlock_OverlappingAreas
  [ International
@@ -2277,6 +2323,7 @@ CheckForOverlappingAreas Entry "r0-r5"
         STR     r0, [sp]
         EXIT
 
+ [ MEMM_Type != "Linux"
 ; Now, check against DAList
 
 30
@@ -2298,12 +2345,14 @@ CheckForOverlappingAreas Entry "r0-r5"
         CMP     r3, r1                                  ; if start of our area is >= end of dyn, then go onto next area
         BCS     %BT40
         B       %BT20                                   ; else it overlaps
+ ]
 
 50
         CLRV                                            ; OK exit
         EXIT
 
 
+ [ PagedMemory
 FixedAreasTable                                         ; table of fixed areas (address, size)
  [ HAL
         &       0,                      AplWorkMaxSize  ; application space
@@ -2337,6 +2386,7 @@ FixedAreasTable                                         ; table of fixed areas (
  ]
  ] ; HAL
         &       -1,                     0               ; termination
+ ] ; PagedMemory
 
 ;**************************************************************************
 ;
@@ -2363,6 +2413,22 @@ AllocateAreaAddress Entry "r0-r2,r4-r7"
         MOVS    r5, r5, LSL #1                          ; double size
         BCS     %FT90                                   ; if that wrapped then that's bad
 05
+ [ MEMM_Type = "Linux"
+        MOV     r0, #0
+        MOV     r1, r5
+        MOV     r2, #PROT_NONE
+        MOV     r3, #MAP_PRIVATE | MAP_ANONYMOUS
+        ORR     r3, r3, #MAP_NORESERVE
+        MOV     r4, #-1
+        MOV     r5, #0
+        LDR     r7, =__NR_mmap2
+        SWI     0xC0000
+        LDR     r4, [sp, #12]
+        MOV     r5, r1
+        CMP     r0, #0xFFFFFF00
+        BHI     %FT90                                   ; Error number returned so failure
+        MOV     r3, r0
+ | ; Linux
         LDR     r3, =DynArea_NewAreasBase               ; r3 is our current attempt
         ADR     r0, FixedAreasTable                     ; r0 is ptr into fixed areas table
         LDR     r1, =ZeroPage+DAList                             ; r1 is ptr into dyn areas list
@@ -2384,6 +2450,7 @@ AllocateAreaAddress Entry "r0-r2,r4-r7"
         MOV     r3, r6                                  ; else make start(ours) := end(next)
         B       %BT10                                   ; and go back for another try
 
+ ] ; Linux
 ; we've succeeded - just apply unbodge for doubly-mapped areas
 
 80
@@ -2405,6 +2472,7 @@ AllocateAreaAddress Entry "r0-r2,r4-r7"
 
         LTORG
 
+ [ PagedMemory
 ;**************************************************************************
 ;
 ;       GetNextRange - Get next lowest range from either fixed or dynamic list
@@ -2608,6 +2676,7 @@ AllocateBackingLevel2 Entry "r0-r8,r11"
   ]
         STR     r0, [sp]
         EXIT
+ ] ; PagedMemory
 
 ;**************************************************************************
 
@@ -2796,6 +2865,7 @@ InitDynamicAreas Entry "r0-r12"
         STMIA   lr, {r0-r8}
 
 
+ [ PagedMemory
 ; We have to move all free pages (ie ones not occupied by the static pages)
 ; into the free pool.
 ; By default, pages will get taken from the end of the free pool when other
@@ -2861,6 +2931,7 @@ InitDynamicAreas Entry "r0-r12"
         LDR     r5, [lr, #DANode_Base]
         SUB     r5, r6, r5
         STR     r5, [lr, #DANode_Size]
+ ] ; PagedMemory
 
 ; Now initialise the system heap by hand, so we can start creating dynamic areas
 
@@ -3172,6 +3243,20 @@ daq_cda_od6done
         ADD     r1, r1, r12
         BICS    r1, r1, r12
         BEQ     IssueServiceMemoryMoved         ; zero pages! (r0 = area number, r1 = size change (0))
+
+ [ MEMM_Type = "Linux"
+        Push    "a3-a4, v1, ip"
+        MOV     v1, r1
+        MOV     a3, r10
+        MOV     lr, pc
+        LDR     pc, =doMoveMemory
+        TEQ     r1, v1
+        Pull    "a3-a4, v1, ip"
+        BEQ     SomeMemoryMoved
+        TEQ     r0, #0
+        ADREQL  r0, ErrorBlock_ChDynamNotAllMoved
+
+ | ; Linux
         BPL     AreaGrow
 
 AreaShrink ROUT
@@ -3600,6 +3685,7 @@ ChangeDynError
 ;       r10 -> area that we tried to shrink/grow
 
         MOV     r1, #0
+ ] ; Linux
 ChangeDynErrorSomeMoved
         STR     r0, [sp]
         LDR     lr, [sp, #10*4]
@@ -3625,9 +3711,9 @@ IssueServiceMemoryMoved
   ]
         Push    "r1"
         MOV     r2, r0                  ; r2 = area number
-        MOV     r0, r1                  ; amount moved (signed)
+        MOVS    r0, r1                  ; amount moved (signed)
         MOV     r1, #Service_MemoryMoved
-        BL      Issue_Service
+        BLNE    Issue_Service
         Pull    "r1"                    ; restore amount moved
   [ DA_Batman
 ISMM_BatCloak
@@ -3705,6 +3791,7 @@ TryToShrinkShrinkables ROUT
         EXIT                                    ; exit CS indicating success
  ]
 
+ [ PagedMemory
 ; ***********************************************************************************
 ;
 ;       DoTheGrow - Do one chunk of growing, small enough to fit into the page block on the stack
@@ -4501,6 +4588,7 @@ DoTheGrowNotSpecified ROUT
 
         CLRV
         EXIT
+ ] ; PagedMemory
 
 ; ***********************************************************************************
 ;
@@ -4587,6 +4675,7 @@ Do_AMB_MakeUnsparse ROUT
         MakeErrorBlock AplWSpaceInUse
         MakeErrorBlock ChDynamCAO
 
+ [ PagedMemory
 ; ***********************************************************************************
 ;
 ;       CallPreShrink - Call pre-shrink routine
@@ -4774,6 +4863,7 @@ CallPostGrow Entry "r0,r3,r4, r12"
         LDMIA   r12, {r12, pc}                          ; load workspace pointer and jump to handler
         FastCDA_ProfEnd CallPostGrow, r12, r4, lr
         EXIT
+ ] ; PagedMemory
 
  [ ShrinkableDAs
 ; ***********************************************************************************
@@ -4817,6 +4907,7 @@ CallTestShrink Entry "r0,r4,r5, r12"
         EXIT
  ]
 
+ [ PagedMemory
 ; ***********************************************************************************
 ;
 ;       MovePageAtR0ToR1WithAccessR6
@@ -4843,6 +4934,7 @@ MovePageAtR0ToR1WithAccessR6ReturnPageNumber Entry "r3-r5,r11"
         MOV     r11, r6
         BL      MoveCAMatR0toR3         ; use old internal routine for now
         EXIT
+ ] ; PagedMemory
 
 ; ***********************************************************************************
 ;
@@ -5199,7 +5291,9 @@ PreGrow_Screen  Entry   "r0-r2,r4"
         TEQ     lr, #0
         SWIEQ   XOS_RemoveCursors               ; if VDU inited, then remove cursors
 
-05      ADRL    r0, PageShifts-1
+05
+ [ PagedMemory
+        ADRL    r0, PageShifts-1
         LDRB    r0, [r0, r5, LSR #12]           ; grab log2Pagesize for shifting
         MOV     r4, r4, LSR r0                  ; change present size into number of pages
                                                 ; since page numbers are 0 to n-1 thus n
@@ -5209,6 +5303,7 @@ PreGrow_Screen  Entry   "r0-r2,r4"
         SUBS    r2, r2, #1                      ; one less to do
         ADDNE   r4, r4, #1                      ; next physical page number
         BNE     %BT10                           ; continue until all pages done
+ ] ; PagedMemory
         CLRV                                    ; ok, so I'm paranoid...
         EXIT
 
diff --git a/castle/RiscOS/Sources/Kernel/s/GenHeader b/castle/RiscOS/Sources/Kernel/s/GenHeader
new file mode 100644
index 0000000..cdbeee7
--- /dev/null
+++ b/castle/RiscOS/Sources/Kernel/s/GenHeader
@@ -0,0 +1,79 @@
+; This source code in this file is licensed to You by Castle Technology
+; Limited ("Castle") and its licensors on contractual terms and conditions
+; ("Licence") which entitle you freely to modify and/or to distribute this
+; source code subject to Your compliance with the terms of the Licence.
+;
+; This source code has been made available to You without any warranties
+; whatsoever. Consequently, Your use, modification and distribution of this
+; source code is entirely at Your own risk and neither Castle, its licensors
+; nor any other person who has contributed to this source code shall be
+; liable to You for any loss or damage which You may suffer as a result of
+; Your use, modification or distribution of this source code.
+;
+; Full details of Your rights and obligations are set out in the Licence.
+; You should have received a copy of the Licence with this source code file.
+; If You have not received a copy, the text of the Licence is available
+; online at www.castle-technology.co.uk/riscosbaselicence.htm
+;
+
+        GET     hdr.GetAll
+
+        MACRO
+        DEFINE  $name
+        DCB     "#define $name (0x", :STR:($name), ")" , 10
+        MEND
+
+        MACRO
+        ZP      $type, $name
+        DCB     "#define $name (*($type *)(ZeroPage + 0x", :STR:($name), "))" , 10
+        MEND
+
+        MACRO
+        HAL     $rtype, $rout, $args
+        DCB     "typedef $rtype (*$rout", "_t)($args);", 10
+        DCB     "#define $rout (($rout", "_t)0x", :STR:(HALWorkspace - 4 * (EntryNo_$rout + 1)), ")", 10
+        MEND
+
+        AREA    Header, DATA, READONLY
+
+        DCB     "#ifndef KERNEL_H", 10
+        DCB     "#define KERNEL_H", 10
+
+        DEFINE  ZeroPage
+        DEFINE  ScratchSpace
+        DEFINE  ScratchSpaceSize
+
+        DEFINE  DynAreaFlags_APBits
+        DEFINE  DynAreaFlags_NotBufferable
+        DEFINE  DynAreaFlags_NotCacheable
+        DEFINE  DynAreaFlags_DoublyMapped
+        DEFINE  DynAreaFlags_NotUserDraggable
+        DEFINE  DynAreaFlags_NeedsSpecificPages
+        DEFINE  DynAreaFlags_Shrinkable
+        DEFINE  DynAreaFlags_SparseMap
+        DEFINE  DynAreaFlags_PiersBinding
+        DEFINE  DynAreaFlags_CPBits
+    [ MEMM_Type = "Linux"
+        DEFINE  DynAreaFlags_FileBacked
+    ]
+
+
+        ZP      uint32_t, Page_Size
+        ZP      uint32_t, RAMLIMIT
+        ZP      uint32_t, AplWorkSize
+
+        ASSERT  DANode_Link = 0 ; because DAList has only link
+        ZP      "struct DANode*", DAList
+        ZP      "struct DANode", AppSpaceDANode
+        ZP      "struct DANode", FreePoolDANode
+        ZP      uint32_t, CDASemaphore
+
+        HAL     "void", "HAL_Init", "unsigned int *riscos_header, void *unacheable_ws"
+
+        DCB     "#endif", 10
+
+        WHILE   ((. - Header) :AND: 3) != 0
+        DCB     10
+        WEND
+
+        END
diff --git a/castle/RiscOS/Sources/Kernel/s/GetAll b/castle/RiscOS/Sources/Kernel/s/GetAll
index 796de98..7c01dfa 100644
--- a/castle/RiscOS/Sources/Kernel/s/GetAll
+++ b/castle/RiscOS/Sources/Kernel/s/GetAll
@@ -23,7 +23,9 @@
 
         GET     s.Kernel
         $GetFlashROM
+        [ PagedMemory
         GET     s.ARMops
+        ]
         GET     s.NewIRQs
         GET     s.Oscli
         GET     s.SysComms
@@ -107,11 +109,13 @@ EndOfPMF
 
         ! 0, "PMF section size = &" :CC: :STR: (EndOfPMF - StartOfPMF)
 
+        [ PagedMemory
 StartOfAMB
         GET     s.AMBControl.AMB
 EndOfAMB
 
         ! 0, "AMB section size = &" :CC: :STR: (EndOfAMB - StartOfAMB)
+        ]
 
         IMPORT  EndOfKernel
 
diff --git a/castle/RiscOS/Sources/Kernel/s/HAL b/castle/RiscOS/Sources/Kernel/s/HAL
index f1901e3..7c0f679 100644
--- a/castle/RiscOS/Sources/Kernel/s/HAL
+++ b/castle/RiscOS/Sources/Kernel/s/HAL
@@ -27,6 +27,7 @@ DRAMOffset_PageZero     #       16*1024
 DRAMOffset_L1PT         #       16*1024         ; L1PT must be 16K-aligned
 DRAMOffset_LastFixed    #       0
 
+ [ PagedMemory
 ;        IMPORT  Init_ARMarch
 ;        IMPORT  ARM_Analyse
 
@@ -326,7 +327,7 @@ split_block
         STMDB   v8, {v3, v7}
         STMIA   v8!, {v2, v6}
         B       %BT10
-
+ ] ; PagedMemory
 
 ;void RISCOS_Start(unsigned int flags, int *riscos_header, int *hal_header, void *ref)
 ;
@@ -337,6 +338,7 @@ split_block
 
         ROUT
 RISCOS_Start
+ [ PagedMemory
         TEQ     a4, #0
 01      BEQ     %BT01                           ; Stop here if no RAM
 
@@ -616,6 +618,9 @@ RISCOS_Start
         MOV     a2, #&00400000
         LDR     a3, =(AP_None * L2X_APMult)
         BL      AllocateL2PT
+ |
+        Push    "a1,a2,a3"                      ; Remember our arguments
+ ] ; PagedMemory
 
 ; Bootstrap time. We want to get the MMU on ASAP. We also don't want to have to
 ; clear up too much mess later. So what we'll do is map in the three fixed areas
@@ -635,7 +640,11 @@ RISCOS_Start
         BL      Init_MapIn
 
         ; Allocate workspace for the HAL
+ [ PagedMemory
         ADD     a4, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
+ |
+        LDR     a4, =ZeroPage
+ ] ; PagedMemory
         LDR     a3, [sp, #8]                            ; recover pushed HAL header
         LDR     a1, =HALWorkspace
         LDR     a2, =(AP_Read * L2X_APMult) + L2_C + L2_B
@@ -672,6 +681,7 @@ RISCOS_Start
         MOV     a4, #16*1024
         BL      Init_MapIn
 
+ [ PagedMemory
         ; Map in L1PT
         MOV     a1, v3
         LDR     a2, =L1PT
@@ -761,11 +771,15 @@ RISCOS_Start
         STR     v1, [a1, #InitUsedBlock]
         STR     v2, [a1, #InitUsedEnd]
         STR     a3, [a1, #ROMPhysAddr]
+ |
+        LDR     a1, =ZeroPage
+ ] ; PagedMemory
 
         ; Note the HAL flags passed in.
         LDR     a2, [sp, #0]
         STR     a2, [a1, #HAL_StartFlags]
 
+ [ PagedMemory
         ; Set up a reset IRQ handler (used during RAM clear for keyboard
         ; scan, and later for IIC CMOS access)
         MSR     CPSR_c, #IRQ32_mode + I32_bit + F32_bit
@@ -961,6 +975,7 @@ MMUon_nol1ptoverlap
         SUB     a2, a2, lr
         ADD     a2, a2, a1
         STR     a2, [a1, #InitUsedBlock]
+ ] ; PagedMemory
 
 
 ; Store the logical address of the HAL descriptor
@@ -973,6 +988,7 @@ MMUon_nol1ptoverlap
 
         ChangedProcVecs a1
 
+ [ PagedMemory
         MOV     a1, #L1_Fault
         BL      RISCOS_ReleasePhysicalAddress
 
@@ -989,6 +1005,7 @@ MMUon_nol1ptoverlap
         STR     a1, [a2, #IOAllocLimit]
         LDR     a1, =IO
         STR     a1, [a2, #IOAllocPtr]
+ ] ; PagedMemory
 
         BL      SetUpHALEntryTable
 
@@ -1040,8 +1057,9 @@ MMUon_nol1ptoverlap
 
         CallHAL HAL_KbdScanSetup
 
-        MSR     CPSR_c, #F32_bit+SVC32_mode             ; enable IRQs for scan
+        vMSR    CPSR_c, #F32_bit+SVC32_mode             ; enable IRQs for scan
 
+ [ PagedMemory
 ; Remember some stuff that's about to get zapped
         LDR     ip, =ZeroPage
         LDR     v4, [ip, #ROMPhysAddr]
@@ -1223,7 +1241,9 @@ MMUon_nol1ptoverlap
         ORR     a2, v4, #AP_None * L2X_APMult
         LDR     a1, =CAM
         BL      Init_MapInRAM
+ ] ; PagedMemory
 
+        DebugTX "Allocating stacks"
 ; Allocate the supervisor stack
         LDR     a1, =SVCStackAddress
         ORR     a2, v4, #AP_Read * L2X_APMult
@@ -1255,6 +1275,13 @@ MMUon_nol1ptoverlap
         ORR     a2, v4, #AP_Full * L2X_APMult
         LDR     a3, =32*1024
         BL      Init_MapInRAM
+ [ :LNOT: PagedMemory
+        LDR     a1, =SysHeapAddress + 32*1024
+        MOV     a2, #0
+        LDR     a3, =SysHeapMaxSize - 32*1024
+        BL      Init_MapInRAM                           ; Reserve address space
+ ]
+
 
 ; Allocate the cursor/system/sound block - first the cached bit
         LDR     a1, =CursorChunkAddress
@@ -1268,10 +1295,17 @@ MMUon_nol1ptoverlap
         BL      Init_MapInRAM_DMA
 
  [ LongCommandLines
+KbuffsSizeRounded * (KbuffsSize + &FFF) :AND: &FFFFF000  ;(round to 4k)
         LDR     a1, =KbuffsBaseAddress
         ORR     a2, v4, #AP_Read * L2X_APMult
-        LDR     a3, =(KbuffsSize + &FFF) :AND: &FFFFF000  ;(round to 4k)
+        LDR     a3, =KbuffsSizeRounded
         BL      Init_MapInRAM
+  [ :LNOT: PagedMemory
+        LDR     a1, =KbuffsBaseAddress + KbuffsSizeRounded
+        MOV     a2, #0
+        LDR     a3, =KbuffsMaxSize - KbuffsSizeRounded
+        BL      Init_MapInRAM                           ; Reserve address space
+  ]
  ]
 
  [ HiProcVecs
@@ -1282,6 +1316,16 @@ MMUon_nol1ptoverlap
         BL      Init_MapInRAM
  ]
 
+ [ :LNOT: PagedMemory
+ ; Reserve application space
+        MOV     a1, #&8000
+        MOV     a2, #0
+        RSB     a3, a1, #AplWorkMaxSize
+        BL      Init_MapInRAM
+ ]
+
+
+ [ PagedMemory
  [ MinorL2PThack
 ; Allocate backing L2PT for the free pool
         MOV     a1, #FreePoolAddress
@@ -1334,16 +1378,18 @@ MMUon_nol1ptoverlap
         BNE     %BT35
 40
         Pull    "v1-v7"
+ ] ; PagedMemory
 
-        MSR     CPSR_c, #F32_bit+I32_bit+IRQ32_mode
+        vMSR    CPSR_c, #F32_bit+I32_bit+IRQ32_mode
         LDR     sp, =IRQSTK
-        MSR     CPSR_c, #F32_bit+I32_bit+ABT32_mode
+        vMSR    CPSR_c, #F32_bit+I32_bit+ABT32_mode
         LDR     sp, =ABTSTK
-        MSR     CPSR_c, #F32_bit+I32_bit+UND32_mode
+        vMSR    CPSR_c, #F32_bit+I32_bit+UND32_mode
         LDR     sp, =UNDSTK
-        MSR     CPSR_c, #F32_bit+SVC2632
+        vMSR    CPSR_c, #F32_bit+SVC2632
         LDR     sp, =SVCSTK
 
+ [ PagedMemory
         LDR     ip, =CAM
         STR     ip, [v8, #CamEntriesPointer]
 
@@ -1353,6 +1399,7 @@ MMUon_nol1ptoverlap
         STR     a1, [v8, #Page_Size]
 
         BL      CountPageTablePages
+ ] ; PagedMemory
 
  [ {FALSE}
         MOV     a1, #InitIRQWs
@@ -1366,6 +1413,7 @@ MMUon_nol1ptoverlap
 
         LTORG
 
+ [ PagedMemory
  [ MEMM_Type = "VMSAv6"
 HAL_InvalidateCache_ARMvF
         ; Cache invalidation for ARMs with multiple cache levels, used before ARMop initialisation
@@ -2455,12 +2503,14 @@ RISCOS_MapInIO ROUT
 90
         EXIT
 
+ ] ; PagedMemory
 
 ; void RISCOS_AddDevice(unsigned int flags, struct device *d)
 RISCOS_AddDevice
         ADDS    a1, a2, #0      ; also clears V
         B       HardwareDeviceAdd_Common
 
+ [ PagedMemory
 ; uint32_t RISCOS_LogToPhys(const void *log)
 RISCOS_LogToPhys ROUT
         Push    "r4,r5,r8,r9,lr"
@@ -2490,6 +2540,7 @@ RISCOS_LogToPhys ROUT
       ]  
 10
         Pull    "r4,r5,r8,r9,pc"
+ ] ; PagedMemory
 
 ; int RISCOS_IICOpV(IICDesc *descs, uint32_t ndesc_and_bus)
 RISCOS_IICOpV ROUT
@@ -2536,7 +2587,6 @@ SetUpHALEntryTable ROUT
         BHI     %BT30
         MOV     pc, lr
 
-
 NullHALEntry
         MOV     pc, lr
 
@@ -2819,6 +2869,7 @@ DebugTerminal_Wrch
  ]
 
 
+ [ PagedMemory
 Reset_IRQ_Handler
         SUB     lr, lr, #4
         Push    "a1-a4,v1-v2,sb,ip,lr"
@@ -2859,6 +2910,7 @@ Reset_IRQ_Exit
         MSR     CPSR_c, a2
         MSR     SPSR_cxsf, a1
         Pull    "a1-a4,v1-v2,sb,ip,pc",,^
+ ] ; PagedMemory
 
  [ DebugHALTX
 DebugHALPrint
diff --git a/castle/RiscOS/Sources/Kernel/s/Kernel b/castle/RiscOS/Sources/Kernel/s/Kernel
index dc8f9f4..b6e0eea 100644
--- a/castle/RiscOS/Sources/Kernel/s/Kernel
+++ b/castle/RiscOS/Sources/Kernel/s/Kernel
@@ -228,6 +228,7 @@ EndData
 SVCDespatcher ROUT
 
 SWIRelocation * SVCDespatcher-SWIDespatch
+PVOpsRelocation SETA SWIRelocation
 
 SLVK_SetV * {PC}-SWIRelocation
 
@@ -291,6 +292,7 @@ SWIRelocationZeroPage
 ; The SWI Despatch routine
 
 SVC * {PC}-SWIRelocation
+ ! 0,"SVC        at ":CC:(:STR:SVC)
 
         Push    "r10-r12"
  [ SupportARMT
@@ -323,6 +325,8 @@ SVC_CallASWI * {PC}-SWIRelocation       ; CallASWI,CallASWIR12 re-entry point
         LDRLO   pc, [pc, r11, LSL #2]
         B       NotMainMOSSwi + SWIRelocation
 
+PVOpsRelocation SETA 0
+
  ASSERT {PC}-SVCDespatcher = SWIDespatch_Size
 
 ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -876,9 +880,9 @@ $l      ModSWIHashval   $swino, $startreg
 $l      ModSWIHashvalOffset $swino, $startreg
         ADD     $swino, $swino, #ModuleSWI_HashTab
       [ ZeroPage <> 0
-        ASSERT ZeroPage = &FFFF0000
-        ADD     $swino, $swino, #&FF000000
-        ADD     $swino, $swino, #&00FF0000
+        ASSERT  (ZeroPage :AND: &FFFF) = 0
+        ADD     $swino, $swino, #(ZeroPage :AND: &00FF0000)
+        ADD     $swino, $swino, #(ZeroPage :AND: &FF000000)
       ]
         MEND
 
diff --git a/castle/RiscOS/Sources/Kernel/s/Linux b/castle/RiscOS/Sources/Kernel/s/Linux
new file mode 100644
index 0000000..18a2a19
--- /dev/null
+++ b/castle/RiscOS/Sources/Kernel/s/Linux
@@ -0,0 +1,172 @@
+; This source code in this file is licensed to You by Castle Technology
+; Limited ("Castle") and its licensors on contractual terms and conditions
+; ("Licence") which entitle you freely to modify and/or to distribute this
+; source code subject to Your compliance with the terms of the Licence.
+;
+; This source code has been made available to You without any warranties
+; whatsoever. Consequently, Your use, modification and distribution of this
+; source code is entirely at Your own risk and neither Castle, its licensors
+; nor any other person who has contributed to this source code shall be
+; liable to You for any loss or damage which You may suffer as a result of
+; Your use, modification or distribution of this source code.
+;
+; Full details of Your rights and obligations are set out in the Licence.
+; You should have received a copy of the Licence with this source code file.
+; If You have not received a copy, the text of the Licence is available
+; online at www.castle-technology.co.uk/riscosbaselicence.htm
+;
+
+        IMPORT  doMoveMemory
+        IMPORT  do_IMB
+
+        EXPORT  __rt_udiv
+        EXPORT  CheckAppSpace
+
+; Paravirtulation HAL routines
+__ParaVirt_SetCPSR_c    *       ROM + 0x34
+__ParaVirt_GetCPSR      *       ROM + 0x38
+__ParaVirt_FindMode     *       ROM + 0x3C
+__ParaVirt_MOVS_PC_LR   *       ROM + 0x40
+
+; Unimplemnted paged memory SWIs
+SSETMEMC                *       NoSuchSWI
+ReadMemMapEntries_Code  *       NoSuchSWI
+SetMemMapEntries_Code   *       NoSuchSWI
+FindMemMapEntries_Code  *       NoSuchSWI
+MMUControlSWI           *       NoSuchSWI
+AMBControlSWI           *       NoSuchSWI
+
+; More stubs
+RISCOS_AccessPhysicalAddress
+        MOV     a1, a2
+RISCOS_ReleasePhysicalAddress
+RISCOS_MapInIO
+RISCOS_InitARM
+RISCOS_AddRAM
+RISCOS_LogToPhys
+        MOV     pc, lr
+
+DAbPreVeneer ; FIXME
+        DebugTX "Data Abort!?"
+        UND
+
+
+        IMPORT  Init_MapInRAM2
+Init_MapIn
+        MOV     a1, a2
+        MOV     a2, a3
+        MOV     a3, a4
+Init_MapInRAM
+Init_MapInRAM_DMA
+        LDR     pc, =Init_MapInRAM2
+
+
+SyncCodeAreasSWI
+        Push    "lr"
+        BL      SyncCodeAreas
+        Pull    "lr"                    ; no error return possible
+        B       SLVK
+
+SyncCodeAreas
+        TST     r0, #1                  ; range variant of SWI?
+        BEQ     SyncCodeAreasFull
+
+SyncCodeAreasRange
+        Push    "a1-a4, ip, lr"
+        ADD     a3, a3, #4
+        MOV     lr, pc
+        LDR     pc, =do_IMB
+        Pull    "a1-a4, ip, pc"
+
+do_IMB_Range
+        Push    "a1-a4, ip, lr"
+        MOV     lr, pc
+        LDR     pc, =do_IMB
+        Pull    "a1-a4, ip, pc"
+
+SyncCodeAreasFull
+do_IMB_Full
+        Push    "a1-a4, ip, lr"
+        MOV     a2, #0
+        MOV     a3, #0xFFFFFFFC
+        MOV     lr, pc
+        LDR     pc, =do_IMB
+        Pull    "a1-a4, ip, pc"
+
+NullOp
+        MOV     pc, lr
+UND_Op
+        DebugTX "Bad ARMOp"
+        UND
+
+ARM_Analyse
+        MOV     a1, #CPUFlag_32bitOS
+        [ HiProcVecs
+        ORR     a1, a1, #CPUFlag_HiProcVecs
+        ]
+        ORR     a1, a1, #CPUFlag_SplitCache+CPUFlag_SynchroniseCodeAreas
+        ORR     a1, a1, #CPUFlag_BaseRestored
+        ORR     a1, a1, #CPUFlag_No26bitMode
+        ORR     a1, a1, #CPUFlag_LongMul
+
+        ; Check store of PC
+30      STR     pc, [sp, #-4]!
+        ADR     a2, %BT30 + 8
+        LDR     a3, [sp], #4
+        TEQ     a3, a2
+        ORREQ   a1, a1, #CPUFlag_StorePCplus8
+
+        LDR     a2, =ZeroPage
+        STR     a1, [a2, #ProcessorFlags]
+
+        ADR     a1, NullOp
+        STR     a1, [a2, #Proc_Cache_CleanAll]
+        STR     a1, [a2, #Proc_Cache_CleanInvalidateAll]
+        STR     a1, [a2, #Proc_Cache_InvalidateAll]
+        STR     a1, [a2, #Proc_Cache_RangeThreshold]
+        STR     a1, [a2, #Proc_TLB_InvalidateAll]
+        STR     a1, [a2, #Proc_TLB_InvalidateEntry]
+        STR     a1, [a2, #Proc_WriteBuffer_Drain]
+
+        ADR     a1, UND_Op
+        STR     a1, [a2, #MMU_PCBTrans]
+        STR     a1, [a2, #Proc_MMU_ChangingEntries]
+        STR     a1, [a2, #Proc_MMU_ChangingEntry]
+        STR     a1, [a2, #Proc_MMU_ChangingUncachedEntries]
+        STR     a1, [a2, #Proc_MMU_ChangingUncachedEntry]
+        STR     a1, [a2, #Proc_MMU_ChangingUncached]
+        STR     a1, [a2, #Proc_MMU_Changing]
+
+        ADR     a1, do_IMB_Range
+        STR     a1, [a2, #Proc_IMB_Range]
+
+        ADR     a1, do_IMB_Full
+        STR     a1, [a2, #Proc_IMB_Full]
+
+        MOV     a1, #0x1000
+        STR     a1, [a2, #Page_Size]
+
+        MOV     a1, #0x10000000
+        STR     a1, [a2, #RAMLIMIT]
+
+        MOV     ip, lr
+        ADD     a3, a2, #ProcVec_UndInst
+        GetVCpu
+        STR     a3, [a1, #vcpu_vectors]
+        MOV     pc, ip
+
+
+
+ARM_PrintProcessorType
+AMBControl_Init
+        MOV     pc, lr
+
+PageShifts
+        =       12, 13, 0, 14           ; 1 2 3 4
+        =       0,  0,  0, 15           ; 5 6 7 8
+
+MMUCReason_ModifyControl        *       1
+MMUCReason_Flush                *       0
+
+
+        END
diff --git a/castle/RiscOS/Sources/Kernel/s/MemInfo b/castle/RiscOS/Sources/Kernel/s/MemInfo
index 6c8a67f..b2af53a 100644
--- a/castle/RiscOS/Sources/Kernel/s/MemInfo
+++ b/castle/RiscOS/Sources/Kernel/s/MemInfo
@@ -53,26 +53,45 @@ MemReturn
         ExitSWIHandler
 
 30
+ [ PagedMemory
         B       MemoryConvert                   ; 0
+ |
+        B       %BT20
+ ]
         B       %BT20                           ; Reason codes 1-5 are reserved.
         B       %BT20
         B       %BT20
         B       %BT20
         B       %BT20
+ [ PagedMemory
         B       MemoryPhysSize                  ; 6
         B       MemoryReadPhys                  ; 7
         B       MemoryAmounts                   ; 8
         B       MemoryIOSpace                   ; 9
+ |
+        B       %BT20                           ; 6
+        B       %BT20                           ; 7
+        B       %BT20                           ; 8
+        B       %BT20                           ; 9
+ ]
         B       MemoryFreePoolLock              ; 10
         B       %BT20                           ; Reason code 11 reserved (for PCImapping).
+ [ PagedMemory
         B       RecommendPage                   ; 12
         B       MapIOpermanent                  ; 13
         B       AccessPhysAddr                  ; 14
         B       ReleasePhysAddr                 ; 15
+ |
+        B       %BT20                           ; 12
+        B       %BT20                           ; 13
+        B       %BT20                           ; 14
+        B       %BT20                           ; 15
+ ]
         B       MemoryAreaInfo                  ; 16
 40
 
 
+ [ PagedMemory
 ;----------------------------------------------------------------------------------------
 ; MemoryConvert
 ;
@@ -297,7 +316,6 @@ handle_AMBHonesty  ROUT
 
    ] ;ChocolateAMB
 
-
 ;----------------------------------------------------------------------------------------
 ; ppn_to_logical
 ;
@@ -818,6 +836,7 @@ easi_space_table
         DCD     PhysSpace + IOMD_EASI_Base6
         DCD     PhysSpace + IOMD_EASI_Base7
  ] ; HAL
+ ] ; PagedMemory
 
 ;----------------------------------------------------------------------------------------
 ; MemoryFreePoolLock
@@ -872,6 +891,7 @@ MemoryFreePoolLock ROUT
 ; See code on Ursula branch
 
 
+ [ PagedMemory
 ;----------------------------------------------------------------------------------------
 ;RecommendPage
 ;
@@ -1067,6 +1087,7 @@ ReleasePhysAddr
         MOV     r0, r1
         BL      RISCOS_ReleasePhysicalAddress
         Pull    "r0-r3,r12,pc"
+ ] ; PagedMemory
 
 ;----------------------------------------------------------------------------------------
 ;
@@ -1158,23 +1179,29 @@ MAI_UNDStk
         EXIT
 
 MAI_SoftCAM
+ [ PagedMemory
         LDR     r0, =ZeroPage
         LDR     r1, [r0, #CamEntriesPointer]
         LDR     r2, =CAMspace
         LDR     r3, [r0, #SoftCamMapSize]
+ ]
         EXIT
 
 MAI_L1PT
+ [ PagedMemory
         LDR     r1, =L1PT
         MOV     r2, #16*1024
         MOV     r3, r2
+ ]
         EXIT
 
 MAI_L2PT
+ [ PagedMemory
         LDR     r0, =ZeroPage
         LDR     r1, =L2PT
         MOV     r2, #4*1024*1024
         LDR     r3, [r0, #L2PTUsed]
+ ]
         EXIT
 
 MAI_HALWs
diff --git a/castle/RiscOS/Sources/Kernel/s/Middle b/castle/RiscOS/Sources/Kernel/s/Middle
index e70f44c..0cb4569 100644
--- a/castle/RiscOS/Sources/Kernel/s/Middle
+++ b/castle/RiscOS/Sources/Kernel/s/Middle
@@ -317,17 +317,26 @@ SBRKPT ROUT
   ]
         STR     r14, [r10, #15*4]       ; PC of the SWI put in.
         BNE     %FT01                   ; NE if not in user mode
+  [ ParaVirt
+        STMFD   r10!, {r0, r9}
+        GetVCpu
+        LDR     r4, [r0, #vcpu_r13_usr]
+        LDR     r5, [r0, #vcpu_r14_usr]
+        MOV     r0, r10
+        LDMFD   sp, {r1-r3}
+        STMIA   r0!,{r1-r5}             ; user mode case done.
+  |
         STR     r0, [r10], #4
         MOV     r0, r10
         LDMFD   sp, {r10-r12}
-
-  [ SASTMhatbroken
+    [ SASTMhatbroken
         STMIA   r0!,{r1-r12}
         STMIA   r0, {r13_usr,r14_usr}^ ; user mode case done.
         SUB     r0, r0, #12*4
-  |
+    |
         STMIA   r0, {r1-r12, r13_usr, r14_usr}^ ; user mode case done.
         NOP
+    ]
   ]
 
 10      LDR     stack, =SVCSTK
@@ -444,7 +453,7 @@ DEFHN2 MOV  R12, R14
        ADRL R0, CLIEXIT
        MOV  R1, #0
        MOV  R2, #0
-       ADR  R4, UNDEF
+       ADRL R4, UNDEF
        ADRL R5, ABORTP
        ADRL R6, ABORTD
        ADRL R7, ADDREX
@@ -471,8 +480,17 @@ NOCALL  LDR     r0, =ZeroPage               ; default callback routine
         LDR     r0, [r14, #4*16]
         vMSR    SPSR_cxsf, r0
  ]
+ [ ParaVirt
+        GetVCpu
+        LDR     r1, [r14, #13*4]
+        LDR     r2, [r14, #14*4]
+        STR     r1, [r0, #vcpu_r13_usr]
+        STR     r2, [r0, #vcpu_r14_usr]
+        LDMIA   r14, {r0-r12}
+ |
         LDMIA   r14, {r0-r12, r13_usr, r14_usr}^ ; load user's regs
         NOP
+ ]
         LDR     r14, [r14, #4*15]
         MOVS_PC_LR
 
@@ -680,14 +698,18 @@ DumpyTheRegisters  ROUT
         STR     R1, [R0, #(15-8)*4]   ; In the right slot now ...
         TST     R1, #SVC_mode
   ]
-  [ SASTMhatbroken
+  [ ParaVirt
+        MOV     R1, #SYS32_mode       ; SYS mode will do nicely
+  |
+    [ SASTMhatbroken
         STMEQIA R0!,{R8-R12}
         STMEQIA R0, {R13,R14}^        ; user mode case done.
         SUBEQ   R0, R0, #5*4
-  |
+    |
         STMEQIA R0, {R8-R14}^         ; user mode case done.
-  ]
+    ]
         BEQ     UNDEF2
+  ]
 
   [ No26bitCode
         ORR     R2, R1, #I32_bit :OR: F32_bit
@@ -1889,8 +1911,13 @@ osri6_table
     DCD  ZeroPage+ModuleSHT_Entries                   ;10
     DCD  ZeroPage+ModuleSWI_HashTab                   ;11
     DCD  ZeroPage+IOSystemType                        ;12
+ [ PagedMemory
     DCD  L1PT                                         ;13
     DCD  L2PT                                         ;14
+ |
+    DCD  0
+    DCD  0
+ ]
     DCD  UNDSTK                                       ;15
     DCD  SVCSTK                                       ;16
     DCD  SysHeapStart                                 ;17
diff --git a/castle/RiscOS/Sources/Kernel/s/NewIRQs b/castle/RiscOS/Sources/Kernel/s/NewIRQs
index 460e9b7..873eb7c 100644
--- a/castle/RiscOS/Sources/Kernel/s/NewIRQs
+++ b/castle/RiscOS/Sources/Kernel/s/NewIRQs
@@ -81,14 +81,24 @@ Initial_IRQ_Code ROUT
         TEQ      r11, #0
         Pull     "r1-r3, r11, r12, lr", EQ
         vMSREQ   SPSR_cxsf, lr
+  [ ParaVirt
+        Pull     "r0, lr", EQ
+        MOVS_PC_LR EQ
+  |
         Pull     "r0, pc", EQ, ^
+  ]
 
         TST      r11, #CBack_Postpone
         LDREQ    lr, [sp_irq, #4*5]     ; get SPSR off stack
         TSTEQ    lr, #I32_bit :OR: &0F  ; check we came from USR26 or USR32 mode, with IRQs enabled
         Pull     "r1-r3, r11, r12, lr", NE
         vMSRNE   SPSR_cxsf, lr
+  [ ParaVirt
+        Pull     "r0, lr", NE
+        MOVS_PC_LR NE
+  |
         Pull     "r0, pc", NE, ^
+  ]
 
 ; Do a CallBack: asked for, not postponed, and we're returning into USR26/32 mode.
 
diff --git a/castle/RiscOS/Sources/Kernel/s/NewReset b/castle/RiscOS/Sources/Kernel/s/NewReset
index 8b5dedd..9819a18 100644
--- a/castle/RiscOS/Sources/Kernel/s/NewReset
+++ b/castle/RiscOS/Sources/Kernel/s/NewReset
@@ -135,7 +135,9 @@ CmosScreenWillDo
 CONT_Break
         AddressHAL
         MOV     a1, #1
+   [ PagedMemory
         LDR     a2, =L1PT
+   ]
         CallHAL HAL_Reset
   ]
 
@@ -531,6 +533,7 @@ conversionSWIfill
 ; OK, that completes the poking around, some of which is code. Now let's
 ; do a full IMB type thing, to be safe
 ;
+        DebugTX "Before IMB_Full"
         LDR     r0, =ZeroPage
         ARMop   IMB_Full,,,r0
         DebugTX "IMB_Full done"
@@ -970,11 +973,15 @@ WallopDuffOnes
 
         MOV     r1, #ChangeDyn_RamFS    ; Area number
         MOV     r3, #-1                 ; Base address dynamic
+      [ ParaVirt
+        MOV     r4, #AP_RAMDisc         ; Area flags
+      |
         ARM_read_ID r4
         AND     r4, r4, #&F000
         CMP     r4, #&A000
         MOVEQ   r4, #AP_RAMDisc_SA      ; Area flags, if StrongARM  (introduced for Ursula)
         MOVNE   r4, #AP_RAMDisc         ; Area flags
+      ]
       [ {FALSE}
         MOV     r5, #16*1024*1024       ; Limit maximum size to 16MB while fiddling with FileCore
       |
@@ -1577,6 +1584,9 @@ PT_lookup
         BEQ     %FT80
 
 Hortoculture_Kicking
+ [ Machine = "Linux" ; No filesystem yet, so this would break.
+        B       %FT80
+ ]
         MOV     R0, #FSControl_BootupFS
         SWI     XOS_FSControl
         BVC     %FT80
@@ -1615,7 +1625,9 @@ HorologicalDelayLoop2
         LDR     r0, =ZeroPage
         LDR     r0, [r0, #MetroGnome]
         CMP     r0, r3
+ [ Machine != "Linux" ; No interrupts yet, so this would freeze.
         BLO     HorologicalDelayLoop2
+ ]
 
 
 ; Start configured language module if keypad-* wasn't pressed
diff --git a/castle/RiscOS/Sources/Kernel/s/PMF/key b/castle/RiscOS/Sources/Kernel/s/PMF/key
index be922ef..87faef1 100644
--- a/castle/RiscOS/Sources/Kernel/s/PMF/key
+++ b/castle/RiscOS/Sources/Kernel/s/PMF/key
@@ -980,6 +980,8 @@ NULNULList                                      ; list for returning NUL NUL
         =       2, 0, 0
         ALIGN
 
+        LTORG
+
 ; *****************************************************************************
 
 ProcessPendingAlt
diff --git a/castle/RiscOS/Sources/Kernel/s/PMF/osinit b/castle/RiscOS/Sources/Kernel/s/PMF/osinit
index a0531d9..094c0d4 100644
--- a/castle/RiscOS/Sources/Kernel/s/PMF/osinit
+++ b/castle/RiscOS/Sources/Kernel/s/PMF/osinit
@@ -264,6 +264,7 @@ ReadCMOSDefaults
         BICEQ   R1, R1, #KBStat_NoNumLock
         STRB    R1, KeyBdStatus
 
+ [ :LNOT: ParaVirt
         MOV     R0, #SystemSpeedCMOS
         BL      Read
         TST     R0, #&20                ; Cache off when b5 set
@@ -272,6 +273,7 @@ ReadCMOSDefaults
         LDREQ   R1, =MMUC_I + MMUC_C + MMUC_W
         MOV     R0, #MMUCReason_ModifyControl
         BL      MMUControlSub
+ ]
         
  [ ModeSelectors
         BL      Read_Configd_MonitorType
diff --git a/castle/RiscOS/Sources/Kernel/s/SWINaming b/castle/RiscOS/Sources/Kernel/s/SWINaming
index c4a4817..a533ca8 100644
--- a/castle/RiscOS/Sources/Kernel/s/SWINaming
+++ b/castle/RiscOS/Sources/Kernel/s/SWINaming
@@ -253,6 +253,7 @@ Conversion_Swi_Names
         =  0
         ALIGN
 
+        LTORG
 
 SWINotInTable
         SUB     r11, r0, #OS_ConvertHex1
diff --git a/castle/RiscOS/Sources/Kernel/s/Utility b/castle/RiscOS/Sources/Kernel/s/Utility
index b988558..c43f777 100644
--- a/castle/RiscOS/Sources/Kernel/s/Utility
+++ b/castle/RiscOS/Sources/Kernel/s/Utility
@@ -381,6 +381,7 @@ PowerOn_Syntax       * Module_BaseAddr
 
 RMFaster_Code
            Push "lr"
+ [ PagedMemory
            MOV R1, R0
            MOV R0, #ModHandReason_LookupName
            SWI XOS_Module
@@ -396,6 +397,7 @@ RMFaster_Code
            MOV   R0, #ModHandReason_CopyArea
            SWI   XOS_Module
            Pull  PC
+ ]
 
 RMFast_notinROM
            ADRL R0, ErrorBlock_RMNotFoundInROM
-- 
1.8.4.rc3

