@(#)building_vxworks_rom.txt 1.1 How To Build One Big Monolithic Vxworks Embedded Kernel And Put It Into Rom So That Your Front End Doesn'T Really Require The Network. by Dennis Nicklaus December 10, 1998 For Tornado 1 only!!!!!!!!!!!! This is a little instruction set that will show you how to build one big object file which includes the VxWorks kernel and your application code, so that you only need to download one file. Furthermore, and more importantly, this shows you how to build this combined VxWorks and applications object file and install it in FLASH (non-volatile memory). Once you have installed this combined object file in Flash memory, you will boot the PPC directly out of that Flash file and not need to download your vxWorks kernel or application objects from over the net. Theoretically, you can thus immediately begin your front end controlling application without being connected to the Net, or if the net is temporarily down and/or unavailable. Of course, most of the ACNET controls utility depends on having a live network, but if you have local finite state machines or control loops that can work on their own, this lets you start them without the network. These instructions are valid only for Power PCs, the Motorola 2300 and 2600 series, as far as I know. You probably don't want to go through this until your application code is pretty mature. STEP 1. PREPARATION Let your fingernails grow for a few days. You will need them for moving the J15 Jumper header back and forth when you have to revert to PPCBug to reload vxworks after you screw up your FLASH. Step 2. MAKE A BUNDLE Link all of your applications into one file. This isn't absolutely necessary, as you can use as many object files as you want to. But since most people are in the habit of having one object file for their application that they download into vxWorks, I'll assume you want to do this step. The rest of these instructions assume that this file is called myapp.o Step 3. HOW THE PPC ROM IS ORGANIZED The PPC MV2303 and MV2603s have two banks of NV memory, A and B. They aren't technically ROM because you can easily write (reprogram) to them. Bank B is 1 MB of socketed ROM. You put the J15 jumper header over pins 2-3 to make the PPC boot from Bank B. Out of the box, your PPC ought to have PPCBug installed in Bank B. PPCBug is a small little executive kernel that you have to use in order to program the other bank of FLASH memory. You can reprogram the Bank B ROM, but you should NOT. You want to leave PPCBug in bank B, and load vxWorks into bank A. Bank A is 2MB or 4MB of soldered-in FLASH memory. This is where you'll load the vxworks kernel. There are instructions available elsewhere for the initial board setup and programming of Bank A from Bank B PPCBug. Those instructions are out of the scope of this document. But briefly, if you have all the other set-up done (internet address, etc.) and you are booted from Bank B, you need the following niop and pflash commands to download a very simple VxWorks boot kernel: PPC1-Bug>niop Controller LUN =00? Device LUN =00? Get/Put =G? File Name =? mv2303/boot.bin Memory Address =00004000? Length =00000000? Byte Offset =00000000? Bytes Received =&333696, Bytes Loaded =&333696 Bytes/Second =&166848, Elapsed Time =2 Second(s) PPC1-Bug>pflash 4000:fff00 ff000100 Program FLASH Memory (Y/N)? y Step 4. LEARN TO PROGRAM THE BANK A FLASH YOURSELF You don't need to use PPCBug to program bank A Flash memory. It is actually pretty simple. Once put into "read mode", you can pretty much do random-access reads from FLASH. However, a special Flash Read function is provided. Before you can write to Flash, you must erase it. Erasing FLASH is only done on a "per-block" basis --- that is, you erase it a whole block at a time. There is a special Flash Erase function. Once erased, again, you can pretty much do random-access writes, but there is a special Flash write function which it is best to use. The read and write functions take extra care to make sure that non-word boundary starting addresses and non-full-word lengths are properly taken care of. My little tests (e.g. with the vxWorks shell "d" and "m" commands), didn't show me much need for those provisions, but I guess I would still suggest using the special Flash read and write functions just to be sure. The three functions are FlashDevRead, FlashDevEraseBlock, and FlashDevWrite They are in the scm project "flash" (/home/ad_projects/flash/clear) in the file lowlvl.c. The lowlvl.h is also needed for some definitions, such as block boundaries. In lowlvl.h, note that the blocks are NOT all the same size. Play with these functions; learn to use them. They are your friends. Next, you will want a function something like my fileflash() (in the flash scm project, file fileflash.c). This function basically copies a file from disk into the FLASH boot address. All the vxWorks + applications images I have produced easily fit into under 1 MB of FLASH. This leaves the rest of FLASH for you to use as NV storage for your application, if you desire/require it. Step 5. START BUILDING The above has been pretty straightforward. Unfortunately, now things get more complicated. You now have to go build special purpose vxWorks kernels. The path I followed is to build a vxWorks kernel that includes its own symbol table, is put into ROM and is compressed. The symbol table is needed if you want to be able to use the shell to monkey with things. As we use vxWorks here, you usually pick up the symbol table separately from the object file over the network. The kernel is compressed because it saves greatly on the amount of ROM required. You should be familiar with the WindCFG tool. Too bad, because it is pretty useless for this process. You pretty much need to do the "make" by hand, and it isn't pretty. But Kevin Martin and I have made some fixes since I started which now makes it much easier for you. 5.A Modify some files $(BSP_DIR)/config.h $(BSP_DIR)/Makefile $(TGT_DIR)/config/all/configAll.h BSP_DIR will typically be /usr/wind_ppc/target/config/mv2303 TGT_DIR will typically be /usr/wind_ppc/target 5.A.i config.h This is the easiest modification to make. All you need to do is make sure that the difference between RAM_HIGH_ADDRS and RAM_LOW_ADDRS is big enough to hold your final, bundled, uncompressed VxWorks image file. RAM_HIGH_ADDRS has generally been about 0x200000 by default. For the Frig application, I had to increase it to about 0x400000, and things just fit. I would guess that the 0x400000 value is a good starting point for you, because Frig has about as much code as any front end would ever want. You won't *know* if this is sufficient until later in the process. 5.A.ii Makefile Make the definition of RAM_HIGH_ADDRS in Makefile the same as in config.h. 5.A.iii configAll.h When you build the vxWorks kernels via a command line "make" (as you must do in this case) instead of the WindCFG Configure and Build commands, you have to manually indicate which features to include and exclude. This is done through the file: $(TGT_DIR)/config/all/configAll.h There is a copy of the version of configAll.h that I used in building the Frig kernel in the file configAll.h.frig. It's a pretty generic configuration that you might find suitable. 5.B Start issuing commands. 5.B.i General Configuration I'm not sure if this step is absolutely necessary, but I think it is. First, use the WindCFG tool to configure and build a vxWorks kernel pretty much the way you'd want it if you weren't putting it into rom and weren't linking your application into it, EXCEPT, you probably have to make (at least) two changes. Add: INCLUDE_STANDALONE_SYM_TBL to the Included Options side. Move: INCLUDE_NET_SYM_TBL to the Excluded Options side. Then push the Configure and Build buttons. Let it finish building. 5.B.ii First make attempt "cd" to the appropriate BSP directory, e.g. % cd /usr/wind_ppc/target/config/mv2303 Get rid of old junk lying around: % make clean Now run your first pass through make with a command like this: % make vxWorks.st_rom ADDED_MODULES=/home/ad_projects/myapp/clear/myapp.o vxWorks.st_rom is the target which includes its own symbol table and is compressed and is to be loaded into ROM for booting. You specify your application objects that you want to link in with the ADDED_MODULES definition. If your make ends with error messages like this: symTbl.c:56: nondigits in number and not hexadecimal symTbl.c:56: syntax error before `00013a2c' make: *** [vxWorks.st.Z.s] Error 1 Then look at the file $(TGT_DIR)/h/make/rules.bsp and the information there about KEEP_SYMTAB. We believe we have fixed this problem so that it should not arise for you, but if it does, that KEEP_SYMTAB stuff in rules.bsp gives you a work-around. 5.B.iii Check the Object Size As part of the build process, an intermediate step is: "ldppc -o tmp.2" This tmp.2 file is basically the UNcompressed objectfile that then gets compressed and wrapped up in some uncompression code before being made ready for downloading to ROM. So I have also added a couple statements to the rules.bsp Makefile inclusion to check how big that is. I do "ls -l" and "vxsize" to test the size. The "ls -l" is really superfluous, just there fyi. But vxsize checks to see if the final object, once it gets uncompressed at boot time, will fit in the allotted space, between RAM_LOW_ADDRS and RAM_HIGH_ADDRS, as seen in step 5.A.i. The output from it will look something like this: VX_CPU_FAMILY=ppc /usr/wind_ppc/host/parisc-hpux9/bin/vxsize -v 00400000 00100000 tmp.2 tmp.2: 1119872(t) + 237596(d) + 1079352(b) = 2436820 (1788260 bytes left) First, note that vxsize is a total idiot of a program. It can't subtract properly, apparently. (It does work for smaller sized object files, I have no idea why it starts failing when they get up over 2 MB, but it does.) Note that we have 0x300000 bytes of space available (3MB), but vxsize apparently thinks we have 4MB. 2436820 +1788260 is not = 3 MB. So you have to check vxsize for yourself to make sure you have allocated enough room in ram for the uncompressed object. Compare the total (2436820) with the space you have available (3MB in this case). If your total exceeds the space available, then go back to 5.A.i and start over. 5.B.iv Finishing up. Note that make also runs something called "romsize" to check whether your final product will fit in your ROM or not. I don't think romsize works very well either, actually. You have to do one more step to make your final product: % elfToBin vxWorks.st_rom.bin vxWorks.st_rom.bin is the final product which you will load into FLASH. Now check out how big it is. % ll vxWorks.st_rom.bin -rw-r--r-- 1 nicklaus ad_microp 605288 Dec 3 17:09 vxWorks.st_rom.bin And make sure it will fit into the amount of FLASH/ROM that you were intending to use. 6. LOAD IT UP To load your .bin file into FLASH, you could move it into the tftp area (which requires root access), switch back to PPCBug from Bank B, and use niop to download it. But that wouldd be a lot of work for no real reason. Instead, you can just write the file contents directly into FLASH, using the functions you learned about in Step 4. You have to write the file into FLASH starting at FLASH address 0x100. Remember you have to first erase all the FLASH blocks that you will be using. I have written a function fileflash(), found in the flash scm project, file fileflash.c, which does the required FLASH programming. Look at the source code to know how to use it. Briefly, to load the above file, you would call: fileflash("vxWorks.st_rom.bin",605288) Now reboot, and away you go! 7. ADDING A CALL TO YOUR ENTRY POINT FUNCTION You need to change the file: $(TGT_DIR)/config/all/usrConfig.c There is a line in there: #undef INCLUDE_USER_APPL You need to get rid of that. (or comment it out). Then right below that, notice that there is the following: #ifdef INCLUDE_USER_APPL /* Startup the user's application */ USER_APPL_INIT; /* must be a valid C statement or block */ You need to change USER_APPL_INIT to be a valid C statement, probably a function call to your own initialization function. After you make this change, you need to go through and rebuild, of course. See for example, usrConfig.c.frig. 8. WHAT'S MISSING IN THIS PICTURE Your application probably isn't really independent of the network just yet. You can use other parts of FLASH to store various parameters or set-up values, things that might be in your start-up script at present. If you still specify a startup script, then when your processor boots, it will try to go over the network to try to find and read this startup script file. If it can't get to the network (connection broken, network down,...) the processor will hang indefinitely waiting to get that file. So if you want to be network independent, don't have a startup script specified through vxWorks bootChange(). Instead, you can put the equivalent of searching for a startup script in your own init functions, where you can control what happens if the network isn't available. Also note, if you have a vxWorks kernel file specified through bootChange(), but then you boot out of ROM like this method describes, the bootChange()-specified vxWorks kernel file not be loaded. The Frig project also has a simple shell script file which is used to copy in the Frig versions of the VxWorks files, make, then restore the original VxWorks file versions. 9. JUST BIZARRE If you have a global variable which starts with the string "Global", or maybe it's just with a capital G, I don't know what the actual key is, that global variable will NOT make it into the symTbl.c file. Since the variable name is not in symTbl.c, you won't be able to use it from the shell. I don't know why this is. Maybe it has something to do with the -X flag to ld. (Although nothing in the ld man page would reinforce that belief.)