Hi! In lesson 4, I might have only used the definition of factorial that used the word 'recurse', and just skipped 'recursive'. 'recurse' is ever so much nicer, don't you think?
<Mitch> I don't have a strong opinion about recurse vs. recursive. Both get the job done.
Thanks for the awesome intro to forth!
<Mitch> You're welcome, glad you like it.
Questions on building Forth firmware
How do I build the firmware? I want to add some new words and some games.
svn co svn://openbios.org/openfirmware cd openfirmware/cpu/x86/pc/olpc/build make
The whole process takes less than a minute if you have a reasonably fast Internet connection.
You can put new "fload" commands in openfirmware/cpu/x86/pc/olpc/fw.bth to include the files defining your new features.
What I am trying to do is automatically, during a boot, over-clock my XO. What file can I modify to execute my new word or words?
- If you want to build a new firmware image, you can cause it to execute your new words automatically by calling them inside the definition "startup", which is defined in the file "openfirmware/cpu/x86/pc/olpc/fw.bth
- Alternatively, you can do it without building new firmware simply by putting your new definitions inside the file "/boot/olpc.fth" on the boot device (which is typically the NAND FLASH, but might also be a USB key or SD card). On a system with security turned off, OFW boots by interpreting Forth source code from that file. That file normally contains code to look for updates, then sets up the cmdline and ramdisk and re-executes the "boot" command to load the kernel. You can add any additional code that you want to it. On a USB key or SD card, the "/boot/" directory is just "/boot/", but on NAND FLASH, "/boot" is a symlink to "/versions/boot/current/boot", and there is some additional trickery at the OS level to switch versions, so you may need to dig around to find the actual location of /boot/olpc.fth under Linux.
How do I get this new build into my XO?
Put the new image on a USB key (for example in a file named "new.rom") and type:
ok flash u:\new.rom
Thanks for all of the help. I modified the /boot/olpc.fth file and I now run at 564.942 MHz. per "cat /proc/cpuinfo" and I have been running memtest at that speed for several hours with no error. Memtest reports a memory speed of 512 Mbs.
In file openfirmware/dev/mmc/sdhci/sdhci.fth, the definition of the word "size" uses the word "le-l@" which seems to be undefined. I did a grep but found multiple definitions of " le-l@ ". Because of this I am unable to compile q2e45q.rom.
Answer: Fixed by svn 2109. Thanks for the error report. In the future, it would be helpful if you could report such problems via the OLPC issue tracker at dev.laptop.org, reporting against the component "ofw - open firmware". This wiki talk page is a rarely-used communication medium so postings to it can easily be lost, and it is not part of my normal workflow.
BTW is their anything I can do to assist you. Forth programming or testing for the XO-1.75 or the XO-3.0. We have cooperated before when I was porting OFW to the beagleboard. I am quite willing to purchase a development platform to use. I am interested in development and testing of hardware drivers in OFW and in linux.
Answer: Unfortunately, hardware suitable for testing the work I am doing now is in short supply, so there is no reasonable way to obtain a copy for you. Thanks very much for the offer.
Ivan Krstić wrote: (on the VPRI FONC mailing list)
There was an experimental 'fastboot' branch of Open Firmware that allowed an XO to (cold)boot a full image from a separate partition in about 3 seconds from power-on to Linux console. Various practicalities kept it from being used.
Is that branch still available somewhere? Is that work considered "active", "dormant", or "dead" (i.e. OLPC does not intend to pick it up again)?
- Felix Rabe
It was 3-ish seconds from power on to Linux kernel in memory and running. From that point, Linux startup takes however long it takes.
The released Open Firmware (Q2D07 and later) supports partitioning (and hence fast boot). The current origin/stable branch of the OLPC kernel also has partition support enabled in the CaFe NAND driver.
The missing pieces are the initrd and the build procedures for creating the partitioned NAND image. The current initrd startup procedure does a lot of filesystem fiddling to support olpc-update, and that (Python) code doesn't account for the possibility that the boot images might be in a separate partition from the rest of the root filesystem. In principle, the changes should be straightforward, but they aren't there yet.
The OFW "secure filesystem update" code, in which you can copy a NAND image from a USB key to the NAND FLASH, supports partitioning - see http://wiki.laptop.org/go/OFW_NAND_FLASH_Updater
So the mechanism for putting a suitably-partitioned image onto NAND exists. What is missing is for someone to put all the pieces together.
usb key formatting comment
Graphics processor word definitions.
I read in a blog that there is firmware containing words for the xo graphics processor. Is a firmware binary file available or is there an ascii file containing colon definitions for words such as gp-fill available?
GP words for Geode
The XO Open Firmware source code is in a Subversion repository at svn://openbios.org/openfirmware
The display driver is in the subdirectory dev/geode/display/
The graphics processor definitions are in the file gp.fth in that directory.
I compiled the OpenFirmware source which produced "q2e11x.rom".
The logs indicate that the wireless and ec code were included.
I am somewhat scared of flashing this to an XO.
Is there any chance if it compiles to "q2e11x.rom" that it will brick my XO?
Mike Westfield email@example.com
It is unlikely to brick your XO, but the answer to any question that begins "Is there any chance ..." is always yes.
I flashed without any problems. I did notice that memtest now runs. It doesn't run in q2e18 without errors.
Question on Openfirmware (OFW)
I've looked at the source, built it, run it in Qemu (via serial port) and it looks super-cool. I've even got some of the way through the Forth tutorial, although it's painful for a C/C++ programmer of 10 years. Never mind, I figure it should be straightforward to add in my own North/Southbridge initialisation without in-depth knowledge of Forth right? Well...a couple of hours later I'm still scratching my head. The emu target looks like a simpler starting point than OLPC. The FAQ explains how to read/write IO ports which is great, so now all I need to know is where exactly to put the PCI initialisation. The Forth learning curve is a bit depressing - I'm almost considering to pull apart the ROM image and 'patch' it with assembler to do the required init, so please save me from myself and tell me the best way to approach this? Many thanks for reading, and qdos for creating such an amazing work, even if I can't fathom its inner workings, Mike.
- Mitch Bradley replies
It depends on what level of init that you need to do. If it is stuff that must happen before you can use memory, it has to be done in the assembly language code that runs really early. The file that contains said code is cpu/x86/pc/emu/pmreset.bth . (More generally, it's the first file that is added to the list of dropin modules in the master build script. For the emu build, that script is emuofw.bth and the line in question is
" pmreset.di" $add-file
(The ".di" extension is the object file; pmreset.bth is the source, which ends with "writing pmreset.di", thus writing out the binary object file)
For the OLPC build, the corresponding master build script is olpc.bth, and the important line is
" romreset.di" $add-file
for which the source file is romreset.bth. There is some stuff before that to get the OLPC Embedded Controller microcode into the right spot.
So anyway, that's the story for assembly language early init. For initialization that can wait until later, specifically stuff that's unnecessary for memory to work or for talking to a serial port, the usual way of handling it is to create a file with your init code, fload that file in devices.fth, then hook your code into the initializer chain as follows:
stand-init: North Bridge do-my-northbridge-init ;
stand-init: is a clever Forth word that creates a definition named "stand-init" which first calls the previously-existing word named "stand-init", then does whatever else you have written. In this way, you can add or remove initialization without having to edit a master initialization routine. The text right after "stand-init:", in this example "North Bridge", is a status message that is displayed on the serial port just before your code is executed.
There are quite a few examples of the use of stand-init: in the code, as it is the workhorse technique for doing initialization, which after all is one of the major functions of OFW.
The only tricky thing is working out exactly where to load your file - you need to do it after any other initializers that must be done first, and before anything that depends on it having already been done. For core logic stuff like Northbridge/Southbridge, generally you want to do it pretty early in devices.fth . In the emu build, devices.fth loads cpu/x86/pc/biosload/pcinode.fth then uses stand-init: to call an init method in that node. That "biosload" version of pcinode.fth is rather generic, making minimal assumptions about the hardware details. In a more typical port to a specific platform, you would make a separate pcinode.fth file in your platform build directory, populating it with code that knows all about your PCI bus setup (interrupt routing, special initialization, available devsels, ids of pluggable slots, etc.).
Contact me on /server irc.oftc.net , /join #olpc-devel if you want to talk through this.
- Follow-up questions
Wow! That's some answer, thanks a lot. I have one question on early init though. I have three definitions I created to do port output but they do not work as expected, pisa-c! and pisa-l! work, but not pisa-w! which ends up doing the same thing as pisa-l! (32-bit port write). Can you tell me what I'm doing wrong? I need a 16-bit port write.
- pisa-c! ( n a - ) " # dx mov # al mov al dx out " evaluate ;
- pisa-w! ( n a - ) " # dx mov # ax mov ax dx out " evaluate ;
- pisa-l! ( n a - ) " # dx mov # eax mov eax dx out " evaluate ;
-- Mitch Bradley Replies
You need "op:" before the "out". The Forth assembler doesn't use the register name variants to control the operation (i.e. eax and ax behave the same).
: pisa-w! ( n a - ) " # dx mov # ax mov op: ax dx out " evaluate ;
See "port-ww" in cpu/x86/startmacros.fth for an example that does the same thing. That file contains some other macros that you might also find useful for early init.
- More Follow-up
On boot I've got just 'Fort' printed on screen. I added an extra diagnostic (see code below) and that gets printed as well, so the copy to ram seems to work ok. This works fine in Qemu, just not on real hardware. Any ideas?
inflate-base # di mov \ di: RAM address to copy it to cld rep byte movs \ Copy the code to RAM ascii a report \ <----- my debug character gets displayed
inflate-base # ax mov \ Absolute address of memory copy ax call
I really don't like to converse via wiki talk pages. Tell me your email address and I'll answer your questions that way. My email is wmb at firmworks dot com.
shucks, and I was just starting to enjoy this
back to the forth mines...