things to do (or not) in (or near) kernel space

using scheme

actually, a way of accessing hardware from a userspace repl.

taken from newsgroup comp.lang.scheme .. .

From: Rob Warnock (rpw3 (at) rpw3 (dot) org)

+---------------
| Harri Haataja wrote:
| > I find the desire some (esp Linux) people have to push things to
| > kernel space very strange. I would think everything that is
| > possible to do in the much more safe and managed user space,
| > should be kept there.
| 
| I agree for most things, but I can't see a kernel exploration
| system / rapid driver development platform working particularly
| well in user space ;-)
+---------------

Uh... It works *extremely* well, actually! And it's *much* easier
to do debugging when the code-under-test is in user mode! Building
a bringup environment for new (and often initially broken!) hardware
was precisely what I used Scheme for when I first started using it
back at SGI circa 1992!! All I had to do was add a few primitives
in C (dynamically-loadable into SCM, later MzScheme) for poking at
the system & hardware:

 malloc & free  ; Note: *Not* from GC'd space
 mpin  ; Pin a virtual address range of the process
   ;  in physical memory, similar to unix v.7 "sys()".
 vir->phys ; Once you've pinned it, where is it? [Needed for DMA]
 mmap  ; Map the hardware registers into process space.
 peek & poke ; In 8/16/32/64-bit flavors

That was enough to let me do almost complete debugging in user mode of
several generations of networking cards -- multi-port FDDI, Ethernet,
ATM, and HIPPI, to name a few -- including testing of both PIO & DMA
transfers. (That's why you need to "pin" pages, so other processes' data
won't get paged into that spot while you're DMA'ing into it!) The code
looked a bit like this (pardon dusty memories for any mistakes):

 (define bridge-path "/hw/module/1/slot/io3/pci/controller")
 (define big0-path "/hw/module/1/slot/io3/pci/0/usrpci/mem32")
 (define brj (mmap bridge-path 0 #x1000000 1))
 (define dev0cf (+ brj #x20000))
 (define dev0 'notyet)
 (define dev0m 'notyet)
 (let ((tmp (r32 dev0cf)))
   (if (= tmp #x210a9)
     (begin
       (print "FOO present on device 0 - Enabling mem space")
       (w32 (+ dev0cf 4) (logior PCCSR_MASTER_EN PCCSR_MEM_SPACE))
       (print "Mapping a big window")
       (set! dev0 (mmap big0-path (r32 (+ dev0cf #x10)) #x8000000 1))
       (set! dev0m (+ dev0 #x7800000)))))

At that point, "dev0" contained the process-virtual address of the
device's on-board registers, and "dev0m" pointed to its shared memory
buffers. Peeking (r32) and poking (w32) at those addresses, one could
put the device through all of its paces (except interrupts! -- but every
bit that could cause an interrupt had a corresponding pollable flag bit,
so in practice that wasn't a serious limitation).

+---------------
| You may well be right but I can imagine things like rapidly
| prototyping a new file-system might be fun in Scheme?
+---------------

You can do *that* in user mode, too!  It wasn't in Scheme (would have
been easier had it been!), but when consulting for AMD in the late 80's,
I reimplemented the IBM CMS filesystem (at least well enough to
read/allocate/write CMD "mini-disk" user files with that "interesting"
B-tree filesystem they had) completely in user space under Amdahl's UTS-5.

You can do the same in modern Unixes/Linux, too. Just write a user-mode
NFS daemon (one easy way to hook a user process into the filesystem
dispatch) that munges raw partitions into whatever filesystem you like
(the way database vendors do for performance).

IMHO and IME, anything that *can* be done in user mode *should* be done
in user-mode, at least during development.


-Rob

Just go for it! It's really easy to get started:

  1. Run some O/S on your machine that allows you to “mmap()” PCI bus space into user mode (possibly requiring superuser privilege, but hey, it's *your* machine, right?). Note: Some OSs don't provide “mmap()” access though device special files per se, but *do* let you use some other access path, such as /dev/mem, /dev/kmem, or /dev/mmem, etc., to map at least the memory space of I/O busses into use process space.
  1. Run some Scheme on your machine that allows you to dynamically link in libraries at runtime (almost any of the popular ones, at least if the answer to #1 was some flavor of Unix or Linux), or use one of the ones that compile to C and let you link in stuff statically.
  1. Find *some* card or chip whose memory register layout you know. (Older ones are sometimes easier to find documentation for.)
  1. Hack up a peek/poke/mmap/etc. library for your Scheme, map in that card (or chip), and start poking around to see what you can see.

WARNING! It is *very* likely that you will crash the host several times while getting this all to work. DO NOT USE A CRITICAL OR SHARED COMPUTER!