October 8, 2013

Bitfields in Managed Code

What are Bitfields?

If you're asking this question, then you probably should stay away, but I'll answer anyway. A bitfield is a method in C/C++ to map sub-components of a structure that is stored in a primitive type. For example, the LTC6946 synthesizer has several registers each of which is contained in a single byte of data.


ADDRMSB[6][5][4][3][2][1]LSBR/WDEFAULT
h08BSTFILTRFOODR/WhF9
The common method to deal with this register structure is to use bit ANDs and shifts. Ultimately the code is easier to read if we could use something like:
register.bst = true;

C/C++ has a way to make this happen, and at the same time it ensures that limits are set, that is I can't set register.filt to more than 3.
 
struct LTC6946_ReferenceOutput
{
   unsigned out_div : 3;       // Default 0x1 | Output divider value
   unsigned rf_out_pwr : 2;    // Default 0x3 | Output Power
   unsigned ref_buff_filt : 2; // Default 0x3 | Reference input buffer filter
   bool ref_buff_boost : 1;    // Default true | Reference input boost current
};

Now, endianess matters here, so structure the code for the endianess of the system this will run on. Typically managed code will run on a little endian machine so we start with the low order parts of the register.

Adding in a Union

This part is not strictly necessary, but it makes reading and writing to the device much simpler. A union in C/C++ allows two datatypes to occupy the same memory space. In the case of a register it allows us to get access to the underlying value without a bunch of pointer work.

template<typename regType>
union Reg32
{
UInt32 val;
regType reg;
};

template<typename regType>
union Reg16
{
UInt16 val;
regType reg;
};

template<typename regType>
union Reg8
{
Byte val;
regType reg;
};

To use this with the LTC6946_ReferenceOutputStructure we declare a variable of the type:
Reg8<LTC6946_ReferenceOutput>

Managed Code

If you try to use this structure in managed code it won't work. In managed C++ you'll get an error like "error C4368: cannot define 'register' as a member of managed...". The trick is in managed C++ you can use a pointer to the structure. Now we can make this work, but it takes a bit more code than straight C/C++.

Creating the Basics

public ref class LTC6946RefOut
{
public:
LTC6946RefOut() 
{
m_fields = new Reg8<LTC6946_ReferenceOutput>();
}

property unsigned out_div
{
unsigned get() { return m_fields->reg.out_div; }
void set(unsigned value) { m_fields->reg.out_div = value; }
};

property unsigned rf_out_pwr
{
unsigned get() { return m_fields->reg.rf_out_pwr; }
void set(unsigned value) { m_fields->reg.rf_out_pwr = value; }
};

property unsigned ref_buff_filt
{
unsigned get() { return m_fields->reg.ref_buff_filt; }
void set(unsigned value) { m_fields->reg.ref_buff_filt = value; }
};

property bool ref_buff_boost
{
bool get() { return m_fields->reg.ref_buff_boost; }
void set(bool value) { m_fields->reg.ref_buff_boost = value; }
};

property Byte val
{
Byte get() { return m_fields->val; }
void set(Byte value) { m_fields->val = value; }
}

 virtual String^ ToString() override
 {
  return m_fields->val.ToString();
 }

private:
Reg8<LTC6946_ReferenceOutput> *m_fields;
};

This will allow the bitfield to be used in managed code including C# and Visual Basic. There are a few clean up tasks yet to do before the code is complete.

Garbage Collection

To get garbage collection to work properly we need to add the destructor and finalizer methods. Each method should delete the m_fields pointer.
!LTC6946RefOut() 
{
delete m_fields;
}
~LTC6946RefOut() 
{
!LTC6946RefOut();
}

By adding these to the class the managed garbage collection will properly clean up the unmanaged code.

Abstraction

There is a fair amount of code here that can be tedious to re-type. The individual properties that map to fields in the bitfield cannot be abstracted away, but the rest can.
template<typename regType>
public ref class CBitField8 abstract
{
public:
CBitField8()
{
m_fields = new Reg8<regType>();
}

!CBitField8()
{
delete m_fields;
}

~CBitField8()
{
!CBitField8();
}

property Byte val
{
Byte get() { return m_fields->val; }
void set(Byte value) { m_fields->val = value; }
}

virtual String^ ToString() override
{
return m_fields->val.ToString();
}

protected:
Reg8<regType> *m_fields;
};

Repeat for 16 and 32 bit bitfields.

Final Form

After the abstraction is in place our initial class is simplified to:
public ref class LTC6946RefOut : CBitField8<LTC6946_ReferenceOutput>
{
public:
LTC6946RefOut() : CBitField8()
{
}

property unsigned out_div
{
unsigned get() { return m_fields->reg.out_div; }
void set(unsigned value) { m_fields->reg.out_div = value; }
};

property unsigned rf_out_pwr
{
unsigned get() { return m_fields->reg.rf_out_pwr; }
void set(unsigned value) { m_fields->reg.rf_out_pwr = value; }
};

property unsigned ref_buff_filt
{
unsigned get() { return m_fields->reg.ref_buff_filt; }
void set(unsigned value) { m_fields->reg.ref_buff_filt = value; }
};

property bool ref_buff_boost
{
bool get() { return m_fields->reg.ref_buff_boost; }
void set(bool value) { m_fields->reg.ref_buff_boost = value; }
};
};

September 11, 2013

ChromeOS in VMWare Player

Background

Recently my kids have all gotten Chromebooks at school. The high school students bring their Chromebooks home which means I get to play a little with them. Since the Chromebook is the property of the school system I can't actually do much to them, and even the little I can do scares my wife.
So instead I did what all sane people do, I looked around to find out how I can run ChromeOS in a virtual machine.

Available Options

It turns out there isn't really much in the way of a straight up ChromeOS virtual machine. Google doesn't seem to be interested in that market. There are some ChromiumOS virtual machines but they don't integrate as well.
I ran across Jay Lee's post which contains some instructions on converting his supplied VMWare image into a real ChromeOS virtual machine. Pretty much the instructions show you how to run his script which downloads a recovery image from Google onto the virtual machine. The problem is the recent recovery images are bigger than the partition space in his virtual machine. I could likely move and resize partitions to get it to work, but that seemed too likely to fail.
Hexxeh, has made some very good ChromiumOS builds that can install on a real machine, and he has made VMWare and VirtualBox images as well. But these are ChromiumOS which aren't was tightly integrated into the Google ecosystem, plus they don't have flash and a few other things that are only distributed with the ChromeOS.

Creating a ChromeOS Virtual Machine

These instructions are for VMWare Player, but other than the initial changes to the virtual machine, the rest of the instructions are specific to the "guest" machine and have no dependency on the "host" virtualization software. In other words, the VirtualBox image will probably work just as well.

Downloading the Virtual Machine

Head on over to Hexxeh's Chromium OS Builds page. And download the VMWare image of the latest Vanilla build.

Extract the ZIP File

Extract the ZIP file to the location where you want your virtual machine to reside.
The extracted files will be the virtual machine definition (.vmx) and the virtual machine disk (.vmdk). Pay attention to the name of the virtual machine disk file, you will need it in the next step.

Fix the Virtual Machine

Using your favorite text editor, open the .vmx file. One line has to be changed and one line has to be added.

Edit the disk image name.


Find the ide0:0.fileName line, and change the "ChromeOS-Vanilla-VMWare.vmdk" to the name of the .vmdk file extracted from Hexxeh's ZIP file.

Add an Ethernet definition.


Add the following line anywhere in the .vmx file.
ethernet0.virtualDev = "e1000"
Save and close the .vmx file.

Mac Notes

In the following steps you will need to press the Control+Option+F2 and Control+Option+F1 keys. On most Mac keyboards this will require you to use the Fn key as well. It may be helpful to go into System Preferences -> Keyboard and enable the "Use all F1, F2, etc. keys as standard functions keys" option.

Boot the Virtual Machine

You can boot the virtual machine by double clicking on the .vmx file. This will boot into the ChromiumOS, not our final ChromeOS. Make sure that Ethernet is selected in the "Select a network" drop down box, then click "Continue"

Sign Into Chromium

You will have to sign into Chromium using a valid Google account. The guest account cannot make the changes we want to make.
Just sign in as though you were on a web page. Two step verification is also supported, use it.

Logged Into Chromium

Now you should see the pretty Chromium desktop.

Enable Developer Mode

Enabling developer mode is pretty easy, but there are a number of ways found in web searches that do not work.

Go into settings:


Click on the Help menu


Click on the "More info..." link


Under the Channel drop down, select the "Dev - Unstable" option

Prepare to Get the Recovery Image

From the virtual machine press Ctrl+Alt+F2 (or Control+Option+F2 on Mac) to switch to the text console. (You can use Ctrl+Alt+F1/Control+Option+F1 to switch back.)
The username is "chronos", the password is currently "facepunch". Alternate passwords could be "chronos", "password" or nothing.
Once you have successfully logged in, run "sudo bash" to become root. The password will be the same password used to login above.
As root run:
touch /mnt/stateful_partition/.developer_mode # may not be needed
cd /tmp # to get to a read/write partition
wget http://goo.gl/4suhf # to download the script
bash 4suhf # to run the script

An alternate script can be found at:
http://cr-48-ubuntu.googlecode.com/files/overwrite-chromiumos-with-chromeos.sh
This should fix the problem for people experiencing the unexpected token 'newline' error.

Select the Recovery Image 


Most of the images should work. I have only tested the Samsung Chromebook Series 5 550 image.

Once an image is selected it will be downloaded.

When the download is complete it will be unpacked and the image will be written to the virtual disks.

Finally the script will finish. The error on line 939 is not critical. Running any commands now will result in a segmentation fault. When the script is finished the system will be pretty much unresponsive, this is normal.

Restart the Guest Machine

Since the ChromiumOS has been overwritten it will be unresponsive and you will have to "hit the reset button" on the virtual machine. On VMware Player, click on the obvious pause button and choose "Restart Guest".

Ignore the Error Behind the Curtain

When the virtual machine starts you will get a warning that a factory error has been detected. Since you are the factory it is up to you to solve the warning. Just "Skip for now".

 Repeat the Sign-In Steps Above

This is a new ChromeOS, nothing on the previous virtual hard drive has been preserved. You will have to go through the login procedure from above again.

Chrome-Sweet-ChromeOS

Finally you have a complete ChromeOS system.

Caveats

I don't know if this is illegal, immoral or fattening. I can't guarantee that this will work, or that it will not trash every electronic memory you have ever made. I know it worked for me.
Automatic updates may or may not work, and may or may not continue to work. See the gotchas from Jay Lee's post.