Tuesday Mar 24, 2009

Hooray! Acrobat Reader for [Open]Solaris x86

Today truly marks a milestone in the history of Solaris for the x86/x64 platform.  One of the most ubiquitous applications, Adobe Reader (notably Acrobat), is now available on [Open]Solaris for both Sparc and x86.

It's been a long time coming, one argument for the lack of Solaris x86 support till now was that [Open]Solaris didn't have the critical mass.  That's a hard one to swallow for the following reasons:

  • There's been a Solaris Sparc version for a long time.  Solaris x86 downloads outnumber Sparc downloads by a large factor.
  • Versions for AIX and HP-UX, which have a significantly smaller installed base, are available.  Maybe IBM and HP payed a lot of money for this?
  • Until recently there were versions even for the likes of OS/2 and UnixWare.

Perhaps open source alternatives are becoming good enough to pose a threat?  Whatever the reason, we welcome the arrival of Acrobat Reader and Adobe's change of heart.

You can get your copy here.

Happy Downloading!

Wednesday Jan 14, 2009

Overhead in Increasing the Solaris System Clock Rate

In a previous entry entitled Real-Time Java and High Resolution Timers, we discussed how Sun's Java Real-Time System requires access to timers with a resolution greater than the default 10ms to do anything really interesting.   It was also stated that most modern processors have an APIC or Advanced Programmable Interrupt Controller which supports much finer-grained clock tick rates.

Unfortunately there are many instances where a system does indeed contain an APIC, but it is not exposed by the BIOS.  Furthermore, we've found that some of the embedded, low-power x86-based processors do not contain an APIC at all.  For an example, take a look at the AMD Geode LX 800 based fit-PC Slim.

So if you wanted to utilize higher resolution timers for this class of system, you'd have to resort to alternative methods.  Solaris and OpenSolaris provide two /etc/system parameters called hires_tick and hires_hz to facilitate increasing your default system clock tick.  By adding the following line to /etc/system, you'll increase the system clock tick rate from the default of 100 per second to 1,000 per second, effectively changing the clock resolution from 10ms to 1ms.

   set hires_tick=1

If you want to further increase the clock resolution, you can do so via the hires_hz system tunable parameter.  Although formally unsupported, it does work.   In order to, for example, increase the clock tick rate to 10,000, add this to /etc/system:

    set hires_tick=1
    set hires_hz=10000

To achieve the desired effect above, you must include both the hires_tick assignment in addition to setting the hires_hz parameter.

These modifications do not come without side-effects, and depending upon the hardware in question and the granularity of the desired timer resolution, they could be significant.  In short, it takes additional CPU cycles to field all those timer interrupts.  So I thought it'd be interesting to see what effect changing the clock tick rate had on two separate systems.   Here they are:

 System  fit-PC Slim
 Panasonic Toughbook CF-30 (Revision F)
 CPU  AMD Geode LX 800 (500 Mhz)
 Intel Core 2 Duo L7500 1.60GHz
 OpenSolaris Version
 snv_98  snv_101b

The measuring tool used for this simple experiment is vmstat(1m).  Solaris aficionados will likely point out that there are much more accurate alternatives, but I think vmstat(1m) gives a decent feel for what's going on without having to expend a whole lot of extra energy.  In particular we'll look at the following fields returned by issuing a 'vmstat 5', and picking one of the interim samples:

  • in - interrupts per second
  • us - percentage usage of CPU time in user space
  • sy - percentage usage of CPU time in system space
  • id - percentage usage of CPU time idling

The sum of (us + sy + id) should approximate 100%.  The table below shows sample vmstat output on various clock tick settings for our two hardware platforms.

Clock tics/sec
 1000  10000  100000
/etc/system settings
 none (default)
 set hires_tick=1
set hires_tick=1
set hires_hz=10000
set hires_tick=1
set hires_hz=100000
vmstat(5) sample fit-PC
 in: 201
 us: 0
 sy: 1
 id: 99
 in: 2001
 us: 0
 sy: 5
 id: 95
 in: 19831
 us: 0
 sy: 43
 id: 57 

vmstat(5) sample CF-30

 in: 471
 us: 0
 sy: 0
 id: 99
 in: 2278
 us: 0
 sy: 1
 id: 99
 in: 20299
 us: 0
 sy: 5
 id: 95
 in: 200307
 us: 0
 sy: 21
 id: 79


  • The vmstat(5) was let run for about a minute.  The output above shows one of the typical 5 second samples.  The other 5 second samples are almost identical.
  • The user (us) CPU time numbers give us a reasonable idea that these systems were predominantly in an idle state when being sampled.
  • The number of interrupts serviced per second is directly proportional to the clock tick rate.
  • And of course, the larger the number of interrupts, the more system CPU time is required.
  • The amount of overhead taken up by increasing the clock rate is a function of system capability.  The CF-30 not only has a much faster processor, it also has two cores to share the interrupt load.  As such it could accommodate a much higher clock tick rate.  For the fit-PC, performance is impacted profoundly even at modest clock tick rates.

Wednesday Jul 23, 2008

Fast Booting Solaris

A veteran Java ONE keynote presenter, Perrone Robotics has developed some real interesting technologies which take the concept of using autonomous (i.e. unmanned) vehicles to a whole new level.  One of their key ingredients is the MAX software platform which utilizes common commercially available components to enable Perrone to very quickly and cost-effectively retrofit nearly any vehicle in short order.

The MAX robotics platform runs on a (roughly 4" x 6") low-power PC board atop Solaris and Sun's Java Real-Time System (Java RTS).  This combination gives Perrone the ability to leverage the huge Java development community, and assures that their critical software components behave in a predictable and deterministic fashion.

During the Java ONE 2007 conference, I was speaking with Paul Perrone about the notion of creating a minimized version of Solaris over which his platform might run.  The helicopter pictured above, boots from a relatively small (4-8Gb)  IDE flash drive, where standard Solaris takes up a substantial chunk.  It leaves them precious little space to collect valuable information like telemetry or terrain data.  Paul asked to revist this idea for a future project.  That's where we left off.

Not that we've ignored them since, but it wasn't until a year later that small Solaris reared its head again.  In addition to saving space, their main interest in this environment was in seeing how much faster Solaris might boot up.  The ability to be fully functional from power-up in as short a time as possible is of critical importance.

So before investigating what advantages there might be, let's provide some background information:


Two separate systems were used, and for argument's sake, represent two ends of the x86 compute spectrum. 

Embedded Profile
Modern Profile 
System iGologic i84810
Panasonic Toughbook CF-30 (Rev. F)
CPU 1GHz Celeron M
Core 2 Duo L7500 1.60GHz
Disk 4GB Flash IDE Drive
Solid State SATA Drive

Operating Systems

Minimal configurations were created for Solaris 10 08/07 (Update 4) and OpenSolaris Nevada build 93.  These configurations boot entirely into RAM and consume less than 100MB ramdisk space.  With a little more effort they can be may significantly smaller.  The original blog post describing the environment is here.   You can download the framework for these hardware/OS combinations here, and can get a feel for the build environment by taking a look at this README.


Within the context of this discussion, here are the key terms along with their meanings.

Total Boot Time: This is the time it takes from power-up till a user is prompted to log in.  Typically for a full Solaris installation, the windowing system must first start up and present the user with a login screen.  In a minimal Solaris environment, there is no windowing system.  Instead, the total boot time is defined as the time it takes from power-up till a user is prompted with the console login: prompt.

POST Time: POST or Power On Self Test is the time taken by the system at pre-boot to handle things like diagnostics,  BIOS and device initialization.  For this discussion, we'll define POST time as the time it takes from power-up until the user is presented with a GRUB boot menu.  We call out this segment of the total time because in many cases we are at the mercy of the PC/BIOS manufacturer and can't overly influence how quickly or slowly this proceeds.

Solaris Boot Time: The time it takes from being presented with a GRUB boot menu till a Solaris user is prompted to log in.  Again, depending upon whether a windowing system is configured or not, this may represent the time it takes to be prompted with a login screen or console login: prompt respectively.  This represents the segment of time that we can influence.

We can conclude from these definitions that:

   Total Boot Time = POST Time + Solaris Boot Time


Embedded Profile: iGoLogic i84810 system 

Post Time
Solaris Boot Time
Total Boot Time
 Solaris 10 08/07
13 sec
26 sec
39 sec
 OpenSolaris Nevada Build 93
13 sec
18 sec
31 sec 

Modern Profile: Panasonic Toughbook CF-30

Solaris Boot Time
 Total Boot Time
 Solaris 10 08/07
 6 sec
 18 sec
 24 sec
 OpenSolaris Nevada Build 93
 6 sec
 9 sec
 15 sec


1. These times were taken by hand with the stopwatch feature on my Timex.  If anything, the times might be slightly shorter than actually recorded as there is a human delay in reacting to seeing the necessary prompts.  I ran the tests several times, and the same numbers consistently appear.

2. The version of the OS appears to matter a lot, as OpenSolaris nvx_93 boots up nearly twice as fast as Solaris 10 U4 on the same hardware.

3. The type of I/O device subsystem seems to be a big factor too.  For example, by switching out the IDE Flash Drive with a 5400 RPM IDE hard disk, i84810 total boot time decreased by about 6 seconds for both Solaris 10 and OpenSolaris. 

4. The minimal Solaris environment is currently only available in 32-bit mode.

5. With relative ease, Solaris can be configured to boot in less that 10 seconds on modern x86 hardware.  My unofficial record stands at 9 seconds (or slightly less).   No doubt it could boot faster on more robust hardware (eliminating POST time).  Any takers?

Tuesday Jun 17, 2008

Real-Time Java in a Zone

As is often the case, Sun's technologies and offerings are being applied in ways which we hadn't necessarily anticipated.  Yet another example has reared its head in the govenrment/military space where customers have expressed interest in using Sun's Java Real-Time System with Solaris Trusted Extensions.  As it stands right now, Java RTS will neither operate nor install within the confines of such an environment.  Let's investigate why this is so, and see what current opportunities there are for working around this shortcoming.

So what is it that causes Trusted Extensions and Java RTS not to play together nicely?   It happens to revolve around Trusted Extension's extensive usage of Solaris zones to limit access between differing security levels.  Solaris packages must be specifically configured to accommodate zones, which has yet to formally take place with Java RTS.  As zones are a core component of Solaris, we can, for the sake of simplicity, just use standard Solaris to demonstrate how we can work around this temporary limitation.  These modifications should apply to Trusted Extensions just as well.   To get Java RTS to work within a zone, follow these steps:

1. Install the Java RTS cyclic driver (only) in the global zone.

global# pkgadd -d . SUNWrtjc

Processing package instance <SUNWrtjc> from </cyclic/src/packages_i386>
## Installing package <SUNWrtjc> in global zone

Java Real-Time System cyclic driver(i386) 2.1.0,REV=2008.
Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
Use is subject to license terms.
Using </> as the package base directory.
## Processing package information.
## Processing system information.
   5 package pathnames are already properly installed.
## Verifying package dependencies.
## Verifying disk space requirements.
## Checking for conflicts with packages already installed.
## Checking for setuid/setgid programs.

This package contains scripts which will be executed with super-user
permission during the process of installing this package.

Do you want to continue with the installation of <SUNWrtjc> [y,n,?] y

Installing Java Real-Time System cyclic driver as <SUNWrtjc>

2. Create a zone called 'rtjzone':
global# mkdir -p /zone
bash-3.00# zonecfg -z rtjzone
rtjzone: No such zone configured
Use 'create' to begin configuring a new zone.
zonecfg:rtjzone> create
zonecfg:rtjzone> set zonepath=/zone/rtjzone
zonecfg:rtjzone> verify
zonecfg:rtjzone> commit
zonecfg:rtjzone> exit
global# zoneadm list -vc
  ID NAME             STATUS     PATH                           BRAND    IP
   0 global           running    /                              native   shared
   - rtjzone          configured /zone/rtjzone                  native   shared
global# zoneadm -z rtjzone install
Preparing to install zone <rtjzone>.
Creating list of files to copy from the global zone.
Copying <6984> files to the zone.
Initializing zone product registry.
Determining zone package initialization order.
Preparing to initialize <1074> packages on the zone.
Initialized <1074> packages on zone.
Zone <rtjzone> is initialized.
Installation of <1> packages was skipped.
The file </zone/rtjzone/root/var/sadm/system/logs/install_log> contains a log of the zone installation.

3.  Modify the zone to allow access to the cyclic device, and to allow additional privileges

global# zonecfg -z rtjzone
zonecfg:rtjzone> set limitpriv=default,proc_priocntl,proc_lock_memory,proc_clock_highres
zonecfg:rtjzone> add device
zonecfg:rtjzone:device> set match=/dev/cyclic
zonecfg:rtjzone:device> end
zonecfg:rtjzone> verify
zonecfg:rtjzone> commit
zonecfg:rtjzone> exit

global# zoneadm -z rtjzone reboot
Note:  One privilege that is useful with Java RTS is sys_res_config.  This is typically used to assign a real-time process to a processor set.  Unfortunately zones cannot currently be given this privilege.  You can however, from the global zone, assign a processor set to a zone, which might be a reasonable workaround.

4.  Get a copy of the SUNWrtjv package and modify it so that it will install in a zone.  The postinstall script and postremove script must replaced with those provided by these hyperlinks just mentioned.

rtjzone# cd /scratch
rtjzone# ls
SUNWrtjv	postinstall	postremove
rtjzone# cp postinstall SUNWrtjv/install/
rtjzone# cp postremove SUNWrtjv/install/

5. Modify the SUNWrtjv pkgmap file with the appropriate sizes, checksums and last access dates.  The source code for a sample C program, called pkgmap_info, which prints out the necessary information, can be found here.

rtjzone# cd SUNWrtjv
rtjzone# grep post pkgmap 1 i postinstall 5402 42894 1194344457 1 i postremove 2966 34854 1194344457 rtjzone# cp pkgmap_info.c /tmp rtjzone# cc -o /tmp/pkgmap_info /tmp/pkgmap_info.c rtjzone# cd /scratch/SUNWrtjv/install/ rtjzone# /tmp/pkgmap_info postinstall postinstall 5820 9488 1213727841 rtjzone# /tmp/pkgmap_info postremove postremove 3092 45039 1213727538
Replace the postinstall and postremove entries in the pkgmap file with those produced by the pkgmap_info program.  You cannot simply use the example data above because the last access times will not match.  Doing so will cause the install to fail.

6. Install the Java RTS SUNWrtjv package inside the zone.

rtjzone# cd /scratch
rtjzone# pkgadd -d . SUNWrtjv

Processing package instance <SUNWrtjv> from </scratch>

Java Real-Time System runtime environment(i386) 1.5.0_13_Java-RTS-2.0_01-b08_RTSJ-1.0.2,REV=2007.
Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
Use is subject to license terms.

Where should this package be installed? (/opt): /opt

To achieve predictable temporal behavior, the Java Real-Time System
must be granted access to a number of privileged Solaris resources.
By default, access to these privileged resources is only granted to
the superuser (root). They can also be granted to additional users
by creating a rights profile, that is, a collection of authorizations,
that can later be assigned to an administrative role or directly
to a user.

As part of this package installation, a local 'Java Real-Time System User'
rights profile can be created on this machine.
This rights profile should NOT be created if such an action conflicts
with your computer security management policies. If unsure, contact
your system administrator or your computer security manager.
Also refer to the product's release notes for further details regarding
the privileges required by the Java Real-Time System.

Should a local 'Java Real-Time System User' rights profile be created? [y,n] (no): y
Using </opt> as the package base directory.
## Processing package information.
## Processing system information.
## Verifying package dependencies.
## Verifying disk space requirements.
## Checking for conflicts with packages already installed.
## Checking for setuid/setgid programs.

This package contains scripts which will be executed with super-user
permission during the process of installing this package.

Do you want to continue with the installation of <SUNWrtjv> [y,n,?] y


## Executing postinstall script.
Creating the 'Java Real-Time System User' rights profile.

Refer to the 'System Administration Guide: Security Services'
documentation for further information regarding the way to assign the
'Java Real-Time System User' rights profile to users, groups, or
administrative roles using the Solaris Management Console, smc(1M) or
the usermod(1M), groupmod(1M) and rolemod(1M) commands.

Installation of <SUNWrtjv> was successful.

6.  Try running a real-time Java application in the zone.

rtjzone# /opt/SUNWrtjv/bin/java -version
java version "1.5.0_13"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_13_Java-RTS-2.0_01-b08_RTSJ-1.0.2)
Java Real-Time System HotSpot(TM) Client VM (build 1.5.0_13-b08, mixed mode)

We hope to more formally support Solaris zones usage with Java RTS in the future.  In the interim this workaround can help you get started.  Many thanks to Jim Clarke, who did the lion's share of the legwork to find this solution.

Thursday May 29, 2008

Are Solaris RAM Disks Swappable?

As memory access is typically orders of magnitude faster than disk access, the idea of using a part of RAM as an in-memory storage device has been one of the earliest performance optimizations realized by the computer science community.  Even though today this type of optimization takes place transparently inside modern operating systems (via mechanisms like the disk buffer cache),  there are still circumstances where manually creating a RAM disk might still be quite useful.

A Solaris customer using the ramdiskadm(1m) utility to create a Ram disk device for a real-time application posed the following question: "Are RAM disks swappable?". From a real-time perspective, a RAM disk not only yields significantly better seek performance but also provides for more deterministic behavior compared to the traditional rotating disk platter.  The customer's concern here is that, under dire circumstances, is it possible for operating system swap out the RAM disk memory?  Needless to say, if a swap out occurred it would put a big crimp in the real-time application's predictability.

To get an idea of what's going on when a RAM disk is created, let's use the Solaris kstat(1m) kernel statitics utility to see how memory is being allocated.  First let's see what memory looks like before creating a RAM disk:

# pagesize
# kstat -n system_pages | grep pagesfree
       pagesfree                       96334
# kstat -n system_pages | grep pageslocke      pageslocked                     26170

So, on this particular system, where a page is 4096 bytes,  there are currently 96334 pages free, and 26170 pages that are locked.  Now let's create a 50MB RAM disk:

# ramdiskadm -a rd 50m
# ramdiskadm
Block Device                                                  Size 
/dev/ramdisk/rd                                           52428800    Yes 
# kstat -n system_pages | grep pagesfree
       pagesfree                       83507
# kstat -n system_pages | grep pageslocked
       pageslocked                     38988

Let's subtract the original number of pageslocked from the latest value and multiply by the pagesize:

# pagesize
# bc

The increase in locked pages can be attributed to the creation of the RAM disk (50m + a small amount of overhead).  So yes, these pages are locked into memory.  But it would be nice to get a definitive statement on what pageslocked actually means.  According to McDougal, Mauro and Gregg's Performance and Tools: DTrace and MDB Techniques for Solaris 10 and OpenSolaris, pageslocked is "Total number of pages locked into memory by the kernel and user processes".  Furthermore, the man page for plock(3C), a related library routine which enables programmers to lock memory segments, states that "Locked segments are immune to all routine swapping".  What's routine swapping?

Hmm.  Anybody care to shed some light on this?

Monday Apr 21, 2008

Modifying and Respinning a Bootable Solaris ISO Image

As an adjunct to the previous blog post, a slightly customized boot environment capable of enabling serial console kernel debugging was required to diagnose Solaris install problems.  The post itself mentioned that a nice way to accomplish this was to set up PXE network boot via Solaris jumpstart.  It is indeed flexible and enables one to experiment with modifications and quickly test whether they perform as expected.  The one downside to this environment is that an additional DHCP/TFTP boot server has to be configured.  To eliminate that service, you could, once the customizations are well understood, simply create a new version of the Solaris install DVD with your customizations.  Let's run through the process for a simple example.

1. Get a Solaris DVD.  For this example, we'll use an interim build of the upcoming Solaris 10 Update 5.

2. Extract the the entire contents of the DVD.

# lofiadm -a /export/iso/s10x_u5b10_dvd.iso
# mkdir -p /iso
# mount -r -F hsfs /dev/lofi/1 /iso
# cd /iso
# mkdir /export/modified-s10x_u5b10
# find . -depth -print | cpio -pudm /export/modified-s10x_u5b10
4516208 blocks

3. Modify the content contained in /export/modified-s10x_u5b10.  In this case, we'll change the boot/grub/menu.lst file found in this directory to look like:

#pragma ident "@(#)install_menu 1.1 05/09/01 SMI"
serial --unit=0 --speed=9600
terminal serial
title Solaris Serial Console ttya
kernel /boot/multiboot kernel/unix -B install_media=cdrom,console=ttya
module /boot/x86.miniroot

4. Issue the following magic incantation to create a bootable ISO image based on the contents of the /export/modified-s10x_u5b10 directory.

# mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -R -L -r -D -U \\
-joliet-long -max-iso9660-filenames -boot-info-table -o \\
/export/iso/modified-s10x_u5b10.iso /export/modified-s10x_u5b10


Size of boot image is 4 sectors -> No emulation
1.80% done, estimate finish Fri Apr 18 15:55:13 2008
2.25% done, estimate finish Fri Apr 18 15:59:07 2008
2.70% done, estimate finish Fri Apr 18 15:58:37 2008
3.15% done, estimate finish Fri Apr 18 15:58:48 2008

98.43% done, estimate finish Fri Apr 18 15:59:37 2008
98.88% done, estimate finish Fri Apr 18 15:59:37 2008
99.33% done, estimate finish Fri Apr 18 15:59:36 2008
99.78% done, estimate finish Fri Apr 18 15:59:36 2008
Total translation table size: 2048
Total rockridge attributes bytes: 3075577
Total directory bytes: 18921472
Path table size(bytes): 148014
Max brk space used 1b24000
1112471 extents written (2172 MB) 

Voila!  Acknowledgements to Tom Haynes and this blog post which served as an excellent guide.

Monday Apr 14, 2008

Enabling Remote Console Debugging of Solaris x86 Boot/Install

Our partners do a fair amount of business supplying ruggedized Solaris-powered Panasonic Toughbook computers to their US government/military customers.  As a regular part of the product cycle, Sun usually works with both the integrators and Panasonic to assure that as new models become available, Solaris runs on these systems properly.  Furthermore, when we can get our grubby little hands on the systems, we'll run them through our certification suite of tests and formally place them on the Solaris Hardware Compatibility List.  As an example, here's the certification report for one of the versions of the Panasonic Toughbook CF-29.

Panasonic recently introduced a new version of the Toughbook CF-30 (referred to as revision F) which tweaks some of the computer subsystems resulting in an all-too-familiar scenario: namely, these differences cause the current version of Solaris to fail to install.  Note: Solaris is not alone here, all Operating Systems must continually play this cat and mouse game to support the latest hardware/firmware advances.

Our initial hypothesis lead us to believe that the problem was related to the introduction of the Intel ICH8 SATA chipset.  So we called on some of our Solaris I/O experts, based out of Sun's Beijing office, to take a peek at what was going on.  As the laptop is currently in New York, we needed a way for folks half way around the world to have access to this system.  There are lots of mechanisms available to remotely diagnose systems, what's somewhat unique here is the following: (1) the diagnosis takes place very early in the boot stage, way before any windowing or networking is set up and (2) The system in question is a laptop, not a server, where things like Lights Out Management (LOM) service processors are non-existent.

The solution here was to utilize decades old RS-232 technology combined with some of features of the GRUB bootloader.  Here are two requirements needed:

  • A serial connection must be established between the system to be diagnosed, which will be referred to henceforth as the target, and the system which accesses the target which we'll refer to as the remote host.   Unfortunately most laptop manufacturers have seen fit to eliminate serial port connectors in lieu of using USB to serial converters as a replacement technology.  At the early stages of boot, USB/serial capability is not yet available, so these systems are not good candidates for this type of diagnosis.  Thankfully the target in question here, the Panasonic CF-30 Toughbook, still comes with a serial port.
  • A Jumpstart environment capable of installing Solaris on x86/x64 systems is strongly recommended.  As part of the process described below, we'll be modifying the target's GRUB environment  (menu.lst).  If you chose to use a DVD boot/install environment instead, you'd need to modify and burn a new DVD for each change made to the target's boot environment.  It took a bit of time to find the right incantations in the menu.lst file to get what was needed here; continually re-burning DVDs would have been excruciating.  This exercise is left to the reader, here's a good start to understanding the jumpstart setup process.

Here's how to set up the remote console environment:

1. A null modem cable must be physically connected between the remote host and target.  The most common cable required will be a DB-9 female-to-female connector.  Your configuration may vary.

2. Check the BIOS of the remote host and target and make sure serial ports are enabled.

3. Running Solaris on the remote host, we'll be using the tip(1) command to access the target via serial port.  Edit the /etc/remote file and look for the hardwire: entry.  Modify it to look like this:


4. As part of setting up a jumpstart install for the target, a series of files are created in the /tftpboot directory of the jumpstart server.  Under /tftpboot, there should be a custom menu.lst file for each managed install, suffixed by the unique network MAC address of the system in question.  For example, the network MAC address for the CF-30 in question is 0:b:97:db:c0:97.  The related /tftpboot file for the CF-30 turns out to be /tftpboot/menu.lst.01000B97DBC097. As your target will have a different MAC address, it's menu.lst  file will have a different suffix in the /tftpboot directory.  Edit that custom menu.lst file (for example, /tftpboot/menu.lst.01000B97DBC097) to look as follows:

serial --unit=0 --speed=9600
terminal serial
title Solaris_10 s10x_u5b10
kernel /I86PC.Solaris_10-1/multiboot kernel/unix -B console=ttya,install_media= -vkd
module /I86PC.Solaris_10-1/x86.miniroot

The key modifications here involve (1) inclusion of the serial --unit=0 --speed=9600 and terminal serial lines plus (2) additional arguments added to the kernel directive.  Grub is very fussy about the order and placement of arguments; playing around with these will likely change grub's behavior. 

5.  From the remote host, access the serial console of the target by issuing:

$ tip hardwire

6. Inside a terminal window, here's what the serial console looks like, after the system has been power cycled and runs through the POST sequence:

After the miniroot is loaded, you'll be presented with an mdb prompt and a screen which looks like this:

You can now issue mdb commands to diagnose.  In this scenario you should also be able to reboot the  system without any other manual intervention, like this:


Here's what issuing the mdb commands ':c' and '$c' look like in this environment.   From this simple  trace we can ascertain that the SATA drivers were never even loaded.  Turns out this is likely a VM problem.  Here's the filed bug report.

Wednesday Dec 19, 2007

Java RTS 2.0 Update 1 Released

After blogging about the relationship between high resolution timers and Java RTS, a comment was posted by a reader stating that they couldn't use Java RTS 2.0 with the latest Solaris 10 update.  Unfortunately that reader was correct.

At the time of the post, Sun had released Solaris 10 Update 4, while Java RTS 2.0 would only support Solaris 10 update 3.  To further exacerbate the situation, once Sun releases a new version of Solaris, they do their best to encourage users to use the latest version by making it difficult (if not impossible) for them to locate previous update versions.

There is a dependency between the aforementioned high resolution timer interface and Solaris which is update specific.  We're working to rectify this situation, but as the process behind Solaris is deliberately bureaucratic, this might take a while.  In the interim we'll need to keep in better lock step with Solaris releases.

On November 27, Java RTS 2.0 update 1 was released: 

  • It supports the latest Solaris 10 update (called 08/07 or update 4)
  • Support for Java SE has been updated to Java SE 5 update 13
  • A new Java RTS DTrace Provider is available
  • Other enhancements are listed here


Monday Oct 15, 2007

General Purpose Always Wins ... Why Not for the Real-Time Market Too?

The brief but brilliant era of computing has seen companies come and go, many relegated to the ash heap of history because they failed to heed this simple rule:  
  In the long run general purpose solutions will always win out over specialized proprietary ones. 
As a long time employee of Sun Microsystems, I've witnessed firsthand the effects, both positive and negative, that this law has had on my company.  Sun can attribute it's initial meteoric rise to the fact that it offered a viable alternative to the popular minicomputer platform of the day.  The first Sun workstations were built from commercial off-the-shelf components, and although nearly equal in performance to the minicomputer, they were so much more affordable that they became good enough.  And of course over time, as Moore's law might dictate, those initial deficiencies quickly dissipated, and in fact surpassed traditional minicomputer capabilities.
Somewhere along the line Sun lost sight of this ideal and began incorporating more proprietary technology into their products.  At first the strategy appeared to be successful as Sun was well positioned to reap huge benefits during the Internet bubble.  Meanwhile, low-cost general purpose servers were continuously improving.  When the bubble burst they in turn became good enough alternatives to the powerful but costly Sun servers.  The resulting decline of Sun was rapid, and it's taken the better part of a decade for us to recover.   This story has been told -- and will continue to be again and again -- for those refusing to learn this lesson.  A professor of mine once told me, "If there's anything we've learned from history, it's that we haven't learned anything from history".

When markets mature, even those where technology is paramount, economic considerations dominate. General purpose systems scale on every dimension (unit, management, training and integration costs) whereas proprietary systems do not.  A switch to more standard components should in no way be construed as stifling innovation.  Rather, general purpose systems help create new innovation by building from common elements economically appealing in their own right, and presumably even more economically beneficial once combined.1

[1] The above paragraph was taken in bits and pieces from an email exchange with Dave Hofert, Java Embedded and Real-Time Marketing Manager.  His points were so compelling I couldn't help myself.

Real-time industrial controllers could be the next market ripe for disruption.  Admittedly this is an entrenched and conservative lot.  But the economics of general purpose computing cannot be denied.  As organizations strive to further eliminate cost out of their system, revisiting usage and deployment of industrial controllers, typically via custom proprietary PLCs, is falling under review.  Consequently, at the behest of one of the world's largest industrial corporations, Sun has partnered with iGoLogic, a systems integrator, and Axiomtek, an industrial PC board manufacturer, to create the real-time controller platform pictured below.
Among others, here are some of the compelling benefits of this platform: 

  • It's based on standard x86 hardware.  The motherboards aren't much larger than a postcard, are energy efficient, and yet have PC class processing power.  The number of competing manufacturers in this space eliminates vendor lock-in and insures price sensitivity and further rapid innovation.
  • Real-time applications are developed using Sun's Java Real-Time System, enabling you to leverage the largest development community on the planet.  Obscure development languages and highly specialized environments are longer needed.
  • Industrial Networking Protocols (e.g PROFIBUS, EtherCAT) are easily migrated to this platform, partly because of the wealth of development tools available.
  • The system utilizes an IDE flash drive from Apacer.  In addition to eliminating the moving parts associated with a traditional disk drive, it consumes less power and makes the system more resistant to shock and vibration.  Overcoming the longevity limitations of flash memory, Apacer has done some interesting work on wear leveling algorithms effectively extending the lifetime of the flash device well past the expected lifetime of the industrial controller.

Let this be our first salvo fired over the proprietary industrial encampment.  We believe the opportunity is immense, but also understand that to achieve any measure of success, partnering with organizations who are truly experts in this arena is critical.  If you think you can add further value, we'd love to talk.

Tuesday Jun 19, 2007

Real-Time Java and High Resolution Timers

Any modern x86/x64 processor worth its salt comes equipped with an Advanced Programmable Interrupt Controller, or APIC.  Among the features that an APIC provides is access to high resolution timers.  Without such capability, the default interrupt source for timer and cyclic operations has a precision on the order of 10 milliseconds -- hardly fine-grained enough for any serious real-time work.

The cyclic subsystem, introduced in Solaris 8, gives Solaris the capability to support high resolution timers.  The Sun Java Real-Time System version 2.0, available for Solaris on both x86 and Sparc platforms, includes an additional package called SUNWrtjcJava Real-Time System cyclic driver.  This package exposes an interface to the cyclic subsystem, normally only available to the kernel.  For those already familiar with Sun's Java RTS, you've no doubt noticed that you either need to run as superuser or assign a set of fine-grained privileges to an ordinary user account. (sys_res_config, proc_priocntl, proc_lock_memory and proc_clock_highres).  The proc_clock_highres privilege gives access to those timers.

Originally developed on an AMD Athlon-based PC, I recently moved a Real-Time Java project over to my Toshiba Tecra A1 laptop running the same version of Solaris and Java RTS.  With the goal of getting in a little development time during a long flight, that migration suddenly casued timings to be all wrong.  Why, might you ask, would moving an application from one seemingly identical Solaris environment to another cause this unusual behavior?  Turns out that even though the laptop, a Pentium 4M based system, has an APIC, it was never exposed by the laptop BIOS.  In this scenario, regardless what you do from a Solaris perspective, you'll never get access to the high-res timers. 

This phenomenon appears to be most prevelant in laptops.  As they account for about 50% (or more?) of PCs sold today, developers have a realistic chance of running into this situation.  You can issue this magic Solaris incantation to determine if your system has high-res timer support:

   # echo "psm_timer_reprogram::print"  | mdb -k

If anything but 'apic_timer_reprogram' is then displayed, your machine has no exposed APIC, and is probably unsuitable for Java RTS.  In some cases the BIOS may be configurable with regards to APIC support; in many others it is simply not available.

In the absence of an APIC, there is the potential to improve the high-resolution timing by setting the following tunable in /etc/system:

   set hires_tick=1

Following a reboot, this would change the clock tick frequency from 100 to 1000 ticks per second. This frequency can then be further tuned by setting the hires_hz tunable to the desired value:

   set hires_hz=10000

The default value is 1000 ticks per second; higher values are not officially supported.

Note that tuning your machine in this way does not come without cost.  It is likely to degrade overall performance, as the system will need to spend a larger proportion of time handling the larger frequency of clock interrupts.1

   [1] Thank you  Christophe Lizzi for your explanation of the problem and potential workaround.


Monday Jun 11, 2007

Audio Transcript and Slides Available for "Real-Time Java Meets Wall Street"

Better late than never ...

As Promised, you can find the audio transcript for the Java ONE 2007 technical session TS-1205: The Sun  Java Real-Time System Meets Wall Street at the aforementioned link.  The slide deck should also be available there, or can be downloaded here.

Thursday Mar 08, 2007

Crosstool Environment in a Solaris Zone

The task of building Java ME CDC-HI binaries and their associated cross development environments tends to be very linux-centric.  Utilities like Crosstool, which make this process much more tolerable, also make various linux and GNU assumptions that differ from standard Solaris.  By introducing new paths and GNU versions of applications, it is possible to mimic this environment in Solaris.   Furthermore, by creating a new zone with this environment, we can isolate these changes without affecting other Solaris system settings.

1. Create a Solaris zone called 'toolzone'

Note: This step is system specific.  For example, the hostname and IP address for 'toolzone' was predefined.  In addition, the network interface (i.e. 'set physical=iprb0') is likely to be different also.

Here's the command-line session for creating the zone:

phoenix://# mkdir /zone
phoenix://# zonecfg -z toolzone
toolzone: No such zone configured
Use 'create' to begin configuring a new zone.
zonecfg:toolzone> create
zonecfg:toolzone> set zonepath=/zone/toolzone
zonecfg:toolzone> set autoboot=true
zonecfg:toolzone> add net
zonecfg:toolzone:net> set address=toolzone
zonecfg:toolzone:net> set physical=iprb0
zonecfg:toolzone:net> end
zonecfg:toolzone> info
zonepath: /zone/toolzone
autoboot: true
dir: /lib
dir: /platform
dir: /sbin
dir: /usr
address: toolzone
physical: iprb0
zonecfg:toolzone> verify
zonecfg:toolzone> commit
zonecfg:toolzone> \^D

phoenix://# zoneadm list -vc
0 global running /
- toolzone configured /zone/toolzone

phoenix://# zoneadm -z toolzone install
Preparing to install zone <toolzone>.
Creating list of files to copy from the global zone.
Copying <6666> files to the zone.
Initializing zone product registry.
Determining zone package initialization order.
Preparing to initialize <945> packages on the zone.
Initialized <945> packages on zone.
Zone <toolzone> is initialized.
Installation of <2> packages was skipped.
Installation of these packages generated warnings: <SUNWcsu SUNWsogm>
The file </zone/toolzone/root/var/sadm/system/logs/install_log> contains a log of the zone installation.
2.  Configure the zone.

2a. Create a zone-specific /usr/bin directory and copy the contents of the global zone's /usr/bin to this new directory.
phoenix://# mkdir -p /zone/toolzone/usr/bin
phoenix://# cd /usr/bin
phoenix://# tar cf - . | (cd /zone/toolzone/usr/bin; tar xfp -)
2b. Create a loopback mount for toolzone to this new version of /usr/bin:
phoenix://# zonecfg -z toolzone
zonecfg:toolzone> addfs
zonecfg:toolzone:fs> set dir=/usr/bin
zonecfg:toolzone:fs> set special=/zone/toolzone/usr/bin
zonecfg:toolzone:fs> set type=lofs
zonecfg:toolzone:fs> end
zonecfg:toolzone> \^D
2c. Boot and configure the newly created zone:
phoenix://# zoneadm -z toolzone boot
phoenix://# zlogin -C toolzone
2d. Change the path of the default shell to /usr/bin/bash.  This is required for crosstool to operate correctly.
toolzone://# cd /usr/bin
toolzone:bin/# mv sh sh.ORIG
toolzone:bin/# ln -s /usr/bin/bash sh
2e. Create a new user in toolzone.  For this example, we'll use 'cdc'.  This exercise is left to the user.
toolzone://# grep cdc /etc/passwd
cdc:x:600:10:CDC-HI build user:/export/home/cdc:/usr/bin/bash
2f. Create a directoy called /opt/gnulinks and make sure the 'cdc' user owns it.  This directory will house versions and links  to GNU utilities which differ from their Solaris counterparts.
toolzone://# mkdir /opt/gnulinks
toolzone://# chown cdc:staff /opt/gnulinks
toolzone://# ls -ld /opt/gnulinks
drwxr-xr-x 2 cdc staff 512 Jun 19 13:14 /opt/gnulinks

3. As the newly created 'cdc' user, configure the zone to build both the crosstool environment and CDC-HI

3a. Login to the zone as the 'cdc' user.
phoenix://# zlogin -l cdc toolzone
[Connected to zone 'toolzone' pts/6]
Last login: Mon Jun 19 12:57:05 on pts/6
Sun Microsystems Inc. SunOS 5.10 Generic January 2005
3b. To get a zone-specific prompt, you might want to have an entry in ~cdc/.bash_profile like:
export PS1='\\h:\\W/\\$ '
3c.  Create links in /opt/gnulinks/bin which point to GNU versions of unix utilities.  This can be accomplised by executing the gnulinks.sh script which looks like:
GNU_PROGS="ar as egrep grep m4 make nm objcopy objdump strings strip tar thumb"

mkdir -p ${GNULINKS_DIR}
for PROG in ${GNU_PROGS}
ln -s /usr/sfw/bin/g${PROG} ${PROG}

toolzone:~/$ sh gnulinks.sh
3d. Modify PATH of 'cdc' user by putting the following line in ~cdc/.bash_profile:
export PATH=/opt/gnulinks/bin:/usr/sfw/bin:$PATH

toolzone:~/$ which tar

3e.  Build and install GNU specific utilities required for crosstool which differ from those provided by Solaris.  They include binutils, fileutils, gawk(1), patch(1) and sed(1).  A build-gnu-bin.sh is furnished to automate this, and looks like:


mkdir -p ${HOME}/GNU

for PROG in $\*
cd ${HOME}/GNU
PREFIX=`echo ${PROG} | sed 's/-.\*//'`
wget ftp://ftp.gnu.org/gnu/${PREFIX}/${PROG}.tar.gz
tar xzf ${PROG}.tar.gz
cd ${PROG}
./configure --prefix=${GNULINKS_DIR}
make install

toolzone:~/$ sh build-gnu-bin.sh fileutils-4.1 gawk-3.1.5 patch-2.5.4 sed-4.1.4

3f. Create a native version of gcc(1).  The Solaris 10 version of gcc found in /usr/sfw/bin uses the stock Solaris linker, ld(1), found in /usr/ccs/bin.  Later versions of glibc will only accept the GNU version of ld(1).

toolzone:~/$ cd ~/GNU
toolzone:GNU/$ wget ftp://ftp.gnu.org/gnu/gcc/gcc-3.4.3/gcc-3.4.3.tar.bz2
toolzone:GNU/$ bunzip2 gcc-3.4.3.tar.bz2
toolzone:GNU/$ tar -xf gcc-3.4.3.tar
toolzone:GNU/$ cd gcc-3.4.3
toolzone:gcc-3.4.3/$ ./configure --prefix=/opt/gnulinks
toolzone:gcc-3.4.3/$ make
toolzone:gcc-3.4.3/$ make install

3g. Build and install a GNU version of binutils using the aforementioned build-gnu-bin.sh script.


toolzone:~/$ sh build-gnu-bin.sh binutils-2.16

 4a.  As the 'cdc' user, build a cross development environment using crosstool.  These instructions are taken from http://www.kegel.com/crosstool/crosstool-0.43/doc/crosstool-howto.html#quick

toolzone:~/$ cd
toolzone:~/$ wget http://kegel.com/crosstool/crosstool-0.43.tar.gz
toolzone:~/$ tar -xzvf crosstool-0.43.tar.gz
toolzone:~/$ su -
toolzone://# mkdir /opt/crosstool
toolzone://# chown cdc:staff /opt/crosstool
toolzone://# exit
4b. As an example, use these configuration files to build a crosstool for a Sharp Zaurus SL-5000D running OpenZaurus 3.5.1:
toolzone:~/$ cd ~/crosstool-0.43
toolzone:crosstool-0.43/$ cat oz-3.5.1.sh
set -ex

# Really, you should do the mkdir before running this,
# and chown /opt/crosstool to yourself so you don't need to run as root.
mkdir -p $RESULT_TOP

# Build the toolchain. Takes a couple hours and a couple gigabytes.

eval `cat arm-softfloat.dat oz-3.5.1.dat` sh all.sh --notest

echo Done.

toolzone:crosstool-0.43/$ cat oz-3.5.1.dat
4c. Build the toolchain
toolzone:crosstool-0.43/$ sh oz-3.5.1.sh > OUT.oz-3.5.1 2>&1 &

Friday Feb 23, 2007

Solaris Was Real-time Before Real-time Was Cool

In the financial services market, there is a general trend to move key systems close to, or even right inside the exchanges themselves -- the idea being that the nearer you are to the source, the less network infrastructure and latency you'll experience.  With this advantage firms can potentially take on additional transaction loads at higher transaction rates.  These systems typically use the latest Intel or AMD processors and run a commercial distribution of Linux.1

[1] Thank you Eric Bruno for your brief description, and for unknowingly letting me (slightly) plagiarize your comments.

Indeed these co-located systems perform as expected almost all the time.  But there are periodic intervals where the latency increases by several orders of magnitude, the ramifications of which could be financially disastrous.  After eliminating other components, the street seems to be focusing its wrath on commercial Linux distributions and their lack of real-time capabilities.

The linux community is actively working to include underpinnings to support real-time, but as of yet these capabilities are not part of a standard major (i.e. Red Hat, SuSE) distribution.  Instead, an alternate version of linux with real-time extensions is offered.  These extensions are in effect separate non-standard OS releases, and have not had the soak time required by many institutions.

Back in the early 90's, I volunteered to move over to Sun's newly formed SunSoft business unit.  One of it's main charters was to push the concept of running Solaris on alternate, i.e. Intel, platforms.  (Don't get me started here, can you imagine where Solaris would be right now if Sun had actually taken this initiative seriously back then?)  As part of that transition, I had the opportunity to take a Solaris Internals course, and couldn't help but notice the effort put in architecturally to address short latencies.  I still have the course notebook; it is dated September 1993.

The point is Solaris already has the real-time capabilities claimed by these add-on linux extensions.  It is built into the operating system, has been for quite some time, is rock solid and doesn't require any additional components.  A partial list of features include:

  • Real-time Scheduling Class - In order to allow equal opportunity to system resources, traditional Unix schedulers transparently change process priorities to give competing processes a fair chance.  Although well suited for timesharing systems, this is unacceptable real-time behavior.  Since its outset, Solaris through its SVR4 roots, introduced the concept of alternate scheduling classes.  It includes a real-time scheduling class, which furnishes fixed-priority process scheduling at the highest priority levels in the system.
  • Fine-Grained Processor Control / Processor Sets - Solaris allows threads and applications to be bound to specific individual processors. In addition, processors within a system can be grouped together as a processor set and dedicated to real-time tasks.2  Here's a nice article describing processor sets. Dated June 2001,  processor sets have been a part of Solaris since release 2.6.
  • Interrupt Sheltering - Available since Solaris 7, this feature enables CPUs to be sheltered from unbound interrupts.  It can be used in conjunction with processor sets to shelter all CPUs in a processor set.  Note: At least one processor in the system must be kept unsheltered.
  • Priority Inheritance - Priority inversion occurs when a high-priority thread blocks on a resource that is held by a lower-priority thread. A runnable thread with a priority between the high and low-priority threads creates a priority inversion because it can receive processor resources ahead of the high-priority thread. 
To avoid priority inversions with kernel synchronization primitives, Solaris employs a transient priority inheritance protocol. The protocol enables the low-priority thread holding the resource to “inherit” the higher priority of the blocked high-priority thread. This approach gives the blocking low-priority thread the CPU resources it needs to complete its task as soon as possible so that it can release the synchronization primitive. Upon completion, all threads are returned to their respective priorities by the kernel.3
  • High Resolution Timers - Solaris 8 introduces the cyclic subsystem; this allows for timers of much better granularity -- in the microsecond and nanosecond range -- without burdening the system with a high interrupt rate.
  • Memory Locking - The paging in and out of data from disk to memory may be considered normal behavior for virtual memory systems, but it is unacceptable for real-time applications.  Solaris addresses this problem by allowing the locking down of a process' pages into memory, using mlock(3C) or mlockall(3C) system calls.
  • Early Binding - By default, linking of dynamic libraries in the Solaris is done on an as-needed basis. The runtime binding for a dynamically linked function isn't determined until its first invocation. Though flexible, this behavior can induce indeterminism and unpredictable jitter in the timing of a real-time application. To avoid jitter, the Solaris provides for early binding of dynamic libraries. By setting the LD_BIND_NOW environment variable to "1", libraries are bound at application startup time. Using early binding together with memory locking is a very effective approach to avoiding jitter.4

[2,3,4] Shameful plagiarism from Scalable Real-Time Computing in the Solaris ™ Operating Environment. A Technical White Paper. To further prove the maturity of Solaris' real-time features, this document was written in the Solaris 8 time frame.  It was copyrighted in 2000.

So why not give Solaris more consideration?  It's way more mature.  And in the unlikely event (chcukle, chuckle) that a lower-latency OS might not solve all your performance problems, I'd put my money on Solaris and DTrace over anything Linux could offer in finding the real problem.

Wednesday Feb 07, 2007

Framework to Help Create Small Footprint RAM Resident Solaris Configurations

As Sun continues to avail more of its intellectual property to the community, the advantages Sun employees have regarding access to internal resources almost disappear.  In fact now when attempting to post questions to internal Sun mail aliases, I am often times redirected to the community.  The ramifications of this change hit me square in the gut this summer.

Having stumbled upon an internal project investigating how Solaris might be minimized for embedded use, I thought an interesting offshoot of this effort might be to create a ZFS appliance.  This device would boot from flash entirely into RAM, and all state would be maintained by the ZFS volumes.  Turns out this may be a little more tricky than anticipated, and future ZFS enhancements to Solaris (ZFS boot) may make this idea moot.

Based on an OpenSolaris ZFS discussion I initiated, observers went off and wrote about this topic elsewhere, some predicting that Sun would be releasing embedded ZFS appliances.  Whoa, hold on there, not so fast.  We have no plans (at least that I know of) to do any such thing.  This was nothing more than a pet project of mine.  Serves me right for announcing that I was a Sun employee.

But there was some good that came out of this dialog.  In addition to learning the valuable lesson of being careful what you write, interest in the notion of using Solaris as an "embedded" OS was quite apparent.   As a consequence,  I thought it might make sense to publish the basic framework used to create a custom Solaris miniroot.  Included below is the introduction section of the README file: 

1.0 Introduction

With the advent of Solaris 10 Update 1 and its migration to the grub(5) bootloader, it becomes quite feasible and straightforward to consider creating small footprint "embedded" versions of Solaris which boot directly into RAM. This project is based upon work done by Shudong Zhou to create a minimized Solaris for embedded use.  The doc/ directory contains some of the original documentation and scripts used to build such an environment.

It is expected that entities may want to provide further functionality and customizations to this environment. In order to assist in this endeavor, the original work has been enhanced to utilize the Java-based ant(1) build tool. For a further description on how a miniroot image is created, see the section on "Understanding the ant(1) build process".

You can download the framework here

Miscellaneous notes:

  • This framework assumes availability of a standard Solaris distribution.  Although not confirmed, I suspect it may not be real hard to augment for OpenSolaris.
  • The current framework produces a RAM resident version of Solaris that is about 60MB in size.  Note: there is no windowing included.
  • These configs are system specific.  The reference implementation for the included framework is an iGoLogic i84810 motherboard.  Some key specs are:
    • 1 GHz Celeron Processor
    • 512 MB RAM on board
    • Compact Flash slot on bottom of motherboard
    • 146mm x 104mm
    • Runs Solaris 10 U3 out of the box
    • For more info contact iGoLogic an http://www.igologic.com
  • Once an image is created, you'll need to set up grub(5) on your media.  Here's a pointer to a URL explaining Grub on a stick.  A copy of this URL is also included in the framework under the doc/ directory.
  • Here's a picture of the motherboard with ruler included to give you a feel for its size. 


Jim Connors-Oracle


« July 2016