A multiprocessing RISC OS kernel in C
Apache License 2.0
Building with RiscOS build RiscOS/Images/rURZ00-00,fe5
./build: line 130: cd: RiscOS/CKernel/: No such file or directory
arm-linux-gnueabi-gcc-8: error: Modules/*.o: No such file or directory

clearly the directory RiscOS/CKernel/ does not exist.

The recent changes have changed the way things are built.
Perhaps we can have a wiki page on how to build from source?
Also it seems that the build script from the Multithreading branch requires something like INTS setup. No idea what it should be.

Previous builds could be done using:

./build -DSINGLE_CORE -Wno-unused-const-variable -Wno-unused-function -DDEBUG__SHOW_MODULE_INIT

But that will stop already with an error:

Please locate a RiscOS build tree (or a symbolic link to one) as RiscOS

So we probably need to install a RiscOS build tree. Would we be able to just do a checkout in some way?
Do we need the RISC OS Compiler suite to compile it (like we do with RISC OS on Linux)?

I really hope to follow the development by doing builds and simple tests.
Best regards,
Jan Rinze.

When building the latest sources it appears that the file task_slot.h is missing.

An easy way to check if files are either checked-in or not is typing 'git status' on the command line.
That will show the files that are changed as well as the files that are not checked in.

I thought I could convince the original code to do the work for me, but it requires workspace at 0xfaff0000+, and simply providing zeroed memory at that address doesn't allow it to work (see below).

Simple tests show that GSTrans will, given sufficient buffer space:

Return the exact length of the resultant string in R2, but also set the following byte (R1?R2) to '\0'.

Without sufficient buffer space:

Leaves the value of R2 unchanged (the size of the buffer) and update each of those bytes, without writing a terminator character.

I think it's better to work on the C implementation than more tightly couple the ROM to the C kernel.

Notes on calling the ROM code direct:
I get a prefetch abort at 0xfb00004. Some code, a branch at fc020734 is jumping out of the ROM, to faff3360.

fc020734: eabf4b09 b faff3360

// GSInit, from Kernel/s/Arthur2 can be found using 'push>[^\n]*\n[^\n]ldrb\tr1, [r0], #1[^\n]\n[^\n]cmp'
// fc0206c4
// GSRead, 'bne>[^\n]
\n[^\n]ldrb\tr1, [r0], #1[^\n]\n[^\n]*cmp' (then look back to the cpsie before the bic
// fc02073c
// GSTrans, the following 'bic\tlr, lr, #.*0x20000000'
// fc020a50

// They access memory around faff3364, as do a number of modules.
// See hack in ./memory/simple/memory_manager.c
// Kernel/Docs/HAL/Notes has a memory map:
00000000 16K Kernel workspace
00004000 16K Scratch space
00008000 Mem-32K Application memory
0xxxxxxx 3840M-Mem Dynamic areas
F0000000 160M I/O space (growing downwards if necessary)
FA000000 1M HAL workspace
FA100000 8K IRQ stack
FA200000 32K SVC stack
FA300000 8K ABT stack
FA400000 8K UND stack
FAE00000 1M Reserved for physical memory accesses
FAF00000 256k reserved for DCache cleaner address space (eg. StrongARM)
FAF40000 64k kernel buffers (for long command lines, size defined by KbuffsMaxSize)
FAFE8000 32K HAL workspace
FAFF0000 32K "Cursor/System/Sound" block (probably becoming just "System")
FAFF8000 32K "Nowhere"
FB000000 4M L2PT
FB400000 16K L1PT
FB404000 4M-16K System heap
FB800000 8M Soft CAM
FC000000 64M ROM

static bool do_OS_GSInit( svc_registers *regs )
return run_risos_code( regs, 0xfc0206c4 );

Sends a ServiceCall &6f Service_BufferStarting, and gets SWI &62942 Buffer_Register from four places in response, but the module isn't in the active list yet. My understanding comes from this from the RO sources:

"During initialisation, your module is not on the active module list, and so you cannot call SWIs in your own SWI chunk."

Now, it's not calling its own SWIs, but they're coming from modules waiting for the service call, and I can't see anywhere else the module could advertise itself, except if it set up a transient callback.

Maybe ROM modules are special?

Now I've found the system font location in ROM, I'd like to see a lot more textual output on the screen.

I'm thinking that now the framework seems to be stable (I'm no longer getting weird behaviour every Nth time I start the code), I'd like that initialisation to be done in a proper module.

Going along with the idea of not touching the RO code with a barge pole, if I can possibly help it, I'll link in a HAL module that will:

  • Initialise the screen via the BCM mailbox interface, then create the screen DA (number 6)
  • Start a "console" module that will intercept WrchV and display the text on screen (per core: 4, 60 character windows, or 4, 15 line windows, probably the former)
  • Start generating centisecond (or millisecond, we're not on a BBC micro any more) ticks for the kernel to use
  • Eventually, run an Obey file as the start of the boot sequence.

I'm thinking of adding a flag to the module flags, which currently has just a single bit for 32-bit compatiblity, to say Multi-processing compatible. I was going to have r12 point to three words, instead of one:

  1. A lock
  2. Private workspace
  3. Shared workspace

But that's dumb, because then the lock wouldn't be shared between them!

The kernel could lock itself when initialising modules (at least MP modules), and then pass them all the same private word, then they could use a word in the shared workspace as a lock. The only problem would be identifying which core it's running on, if that matters.

I just realised that the copies of the module that are initialised later can simply define the core's DA, which avoids the problem I was anticipating of communicating to each core that there's a new DA; the kernel only has to mark that the virtual memory area is not available to other cores.

Handle the SVC vector, execute the appropriate code, and return.

The handler code will have to preserve call-clobbered registers before calling a routine to find the appropriate code, restore them before jumping to that code, and handle returning to wherever made the call.

Initially, just X-form SWIs, and don't handle error returns.

To manage memory in a RISC OS compatible way.

I have tried various machine configurations with qemu-system-arm but none of them actually did anything.
Would be useful to have some info on how to run qemu since it is mentioned as being used to test.

The build script expects to have a ro_rom.o file in the build tree. However there is no script or description on how to create that file.

undefined reference to 'do_OS_SetVarVal'
undefined reference to 'SetInitialVduVars'

Both functions are referenced but not defined in the source code.

It appears that the directory swis is missing a file : swis/vdu.c

boot/generic/boot.h has a definition of boot_data but should be extern:


diff --git a/boot/generic/boot.h b/boot/generic/boot.h
index bd353fe..01af84b 100644
--- a/boot/generic/boot.h
+++ b/boot/generic/boot.h
@@ -41,5 +41,5 @@ typedef struct {
uint32_t core_entered_mmu;
} startup;

-startup boot_data; // Read-only once MMU enabled
+extern startup boot_data; // Read-only once MMU enabled

Testing on real hardware, rather than QEMU, the claim_lock function blocked in some way.

The LDREX instruction didn't work on an area of shared memory. (There were no vectors set up at that point in the boot sequence, so I can't tell what might have been reported, yet.)

The MMU was enabled (I already knew LDREX/STREX wouldn't work without it), and the memory page was mapped with:
XN = 1
B = 0
C = 0
nG = 0
APX = 0
AP = 1
TEX = 0

Setting B and C to 1, allows progress, but I still want to understand why it failed.

I need to change the permissions on the file, and also work out how github works.