====things to do (or not) in (or near) kernel space==== using [[scheme language|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: - 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. - 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. - Find *some* card or chip whose memory register layout you know. (Older ones are sometimes easier to find documentation for.) - 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!