├── .gitignore ├── README.md ├── _modify_ini.py ├── create_rootfs.sh ├── get_linux.sh ├── params ├── reset.sh └── run_vm.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.img 2 | linux 3 | 4 | mnt 5 | unpacked -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QEMU RoboRIO ARM Virtual Machine 2 | ================================ 3 | 4 | This is a set of scripts that extracts the files for National Instruments 5 | Real Time Linux from the RoboRIO image zipfile, creates an image from them, 6 | and provides a script that allows you to run them via the QEMU emulator. 7 | 8 | What can you use this for? Well, if you need to compile packages that are 9 | difficult to cross compile or build on a resource constrained system, 10 | or do testing that requires an ARM platform but does not require actual 11 | NI hardware.. this might be for you. 12 | 13 | Tested with: 14 | 15 | * Fedora 22/24, OSX (run only) 16 | * QEMU 2.5.0, 2.6.1 17 | * FRC images: 2017v8 and 2016v18 18 | * I tried 2015v23, but there's an error starting the NI configuration daemon 19 | and so ssh refuses to start. 20 | 21 | It probably works on other Linux distributions, and may even work with OSX if 22 | you adjust the scripts to work there. 23 | 24 | Requirements 25 | ------------ 26 | 27 | For creating an image: 28 | 29 | * A linux host with the following installed: 30 | * mkfs 31 | * unzip 32 | * qemu-img, qemu-nbd 33 | * root permissions 34 | 35 | For running the created image: 36 | 37 | * QEMU arm emulator (qemu-system-arm) 38 | * Works on Linux and OSX 39 | 40 | Creating the Virtual Machine root filesystem 41 | -------------------------------------------- 42 | 43 | First, you need the image zipfile that is distributed with the FRC Update Suite. 44 | On a machine with the RoboRIO imaging program installed, you can find it at: 45 | 46 | C:\Program Files (x86)\National Instruments\LabVIEW 2015\project\roboRIO Tool\FRC Images 47 | 48 | Copy the zipfile to your Linux host, and run the following: 49 | 50 | ./create_rootfs.sh /path/to/FRC_roboRIO_*.zip 51 | 52 | Give it a few minutes, enter in your password when prompted, and at the end you 53 | should end up with an image file and a kernel file. This only needs to be done 54 | once. 55 | 56 | Running the Virtual Machine 57 | --------------------------- 58 | 59 | Simple command: 60 | 61 | ./run_vm.sh 62 | 63 | At the moment there are a lot of error messages, but eventually it will finish 64 | starting and you can login via the console or via SSH. 65 | 66 | To SSH into your VM, you can execute the following: 67 | 68 | ssh admin@localhost -p 10022 69 | 70 | Or, you can setup an SSH alias by adding this to `.ssh/config`: 71 | 72 | Host roborio-vm 73 | User admin 74 | Hostname 127.0.0.1 75 | Port 10022 76 | 77 | Then you can login using the following: 78 | 79 | ssh roborio-vm 80 | 81 | Snapshots 82 | --------- 83 | 84 | QEMU has good support for snapshots and other such things. When the rootfs is 85 | created, an initial snapshot is created in case you want to revert the VM 86 | back to a 'pristine' state. To do so: 87 | 88 | qemu-img snapshot -a initial roborio.img 89 | 90 | There is now also a `reset.sh` command that you can run to do this. 91 | 92 | Known issues 93 | ------------ 94 | 95 | * I haven't figured out a good way to safely shutdown the system 96 | * Probably should use a different filesystem for the image 97 | * Lots of error messages on bootup, would be nice if we could use the actual 98 | kernel used on the RoboRIO (this seems like it should be possible) 99 | 100 | Building QEMU from source 101 | ========================= 102 | 103 | Download [latest version of QEMU](http://wiki.qemu.org/Download), and... 104 | 105 | tar -xf qemu-2.6.1.tar.bz2 106 | cd qemu-2.6.1 107 | mkdir build 108 | cd build 109 | ../configure --target-list=arm-softmmu --enable-fdt 110 | make 111 | make install 112 | 113 | Versions of QEMU that I've had work for me: 114 | 115 | * 2.5 116 | * 2.6.x 117 | * 2.8.x 118 | 119 | Versions known to not work: 120 | 121 | * 2.7.0 122 | 123 | Contributing new changes 124 | ======================== 125 | 126 | This is intended to be a project that all members of the FIRST community can 127 | quickly and easily contribute to. If you find a bug, or have an idea that you 128 | think others can use: 129 | 130 | 1. [Fork this git repository](https://github.com/robotpy/roborio-vm/fork) to your github account 131 | 2. Create your feature branch (`git checkout -b my-new-feature`) 132 | 3. Commit your changes (`git commit -am 'Add some feature'`) 133 | 4. Push to the branch (`git push -u origin my-new-feature`) 134 | 5. Create new Pull Request on github 135 | 136 | Authors 137 | ======= 138 | 139 | * Dustin Spicuzza (dustin@virtualroadside.com) 140 | 141 | These scripts are not endorsed or associated with Xilinx, FIRST Robotics, or 142 | National Instruments. 143 | -------------------------------------------------------------------------------- /_modify_ini.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Usage: python _modify_ini.py file.ini section key value 4 | # 5 | 6 | import sys 7 | 8 | try: 9 | from ConfigParser import RawConfigParser 10 | except ImportError: 11 | from configparser import RawConfigParser 12 | 13 | 14 | if __name__ == '__main__': 15 | _, ini, section, k, v = sys.argv 16 | cp = RawConfigParser() 17 | cp.read(ini) 18 | cp.set(section, k, v) 19 | 20 | with open(ini, 'w') as fp: 21 | cp.write(fp) 22 | -------------------------------------------------------------------------------- /create_rootfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | NBD_DEVICE=/dev/nbd0 4 | 5 | cd `dirname $0` 6 | source params 7 | 8 | if [ -f "$IMG_FILE" ]; then 9 | echo "$IMG_FILE already exists! Please delete it if you wish to build a new image" 10 | exit 1 11 | fi 12 | 13 | if [ "$1" == "" ]; then 14 | echo "Usage: $0 /path/to/FRC_roboRIO_*.zip" 15 | exit 1 16 | fi 17 | 18 | ROBORIO_ZIP="$1" 19 | 20 | QEMU_NBD=`which qemu-nbd` 21 | 22 | function abspath { 23 | return "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")" 24 | } 25 | 26 | function rm_mount { 27 | if [ -d mnt ]; then 28 | sudo umount mnt || true 29 | rmdir mnt 30 | fi 31 | } 32 | 33 | function rm_unpacked { 34 | [ ! -d unpacked ] || rm -rf unpacked 35 | } 36 | 37 | function cleanup { 38 | echo "Cleaning up..." 39 | rm_unpacked 40 | rm_mount 41 | 42 | if [ ! -z "$NBD_DEVICE" ]; then 43 | sudo "$QEMU_NBD" -d $NBD_DEVICE 44 | fi 45 | } 46 | 47 | trap cleanup EXIT 48 | 49 | rm_unpacked 50 | rm_mount 51 | 52 | # Unpack the roborio image zipfile, ensure we're sane 53 | mkdir unpacked 54 | 55 | unzip "$ROBORIO_ZIP" -d unpacked 56 | # there are two files in there, one is a zip file, unzip the zip file 57 | mkdir unpacked/more 58 | unzip unpacked/*.zip -d unpacked/more 59 | 60 | # Make sure the file we're looking for is there 61 | if [ ! -f unpacked/more/systemimage.tar.gz ]; then 62 | echo "Error: Expected to find systemimage.tar.gz, did not find it!" 63 | exit 1 64 | fi 65 | 66 | # Create the qemu image 67 | qemu-img create -f qcow2 "$IMG_FILE" $HDD_SIZE 68 | 69 | # Mount it, format it (requires root access!) 70 | sudo modprobe nbd 71 | 72 | sudo "$QEMU_NBD" -d /dev/nbd0 73 | sudo "$QEMU_NBD" -c $NBD_DEVICE "$IMG_FILE" 74 | 75 | echo "Formatting image, this may take a few minutes..." 76 | # TODO: probably should use a different filesystem 77 | sudo mkfs.ext3 $NBD_DEVICE 78 | 79 | mkdir mnt 80 | sudo mount -t ext3 $NBD_DEVICE mnt 81 | 82 | # Untar the file onto the image.. 83 | echo "Unpacking FRC image..." 84 | sudo tar -xf unpacked/more/systemimage.tar.gz --directory mnt 85 | 86 | # Modify the startup configuration to enable SSHD 87 | STARTUP_INI_FILE=mnt/etc/natinst/share/ni-rt.ini 88 | sudo python _modify_ini.py ${STARTUP_INI_FILE} SYSTEMSETTINGS host_name roboRIO-VM 89 | sudo python _modify_ini.py ${STARTUP_INI_FILE} SYSTEMSETTINGS sshd.enabled True 90 | sudo python _modify_ini.py ${STARTUP_INI_FILE} SYSTEMSETTINGS ConsoleOut.enabled True 91 | 92 | # Unmount it 93 | rm_mount 94 | 95 | # Create a snapshot in case someone wants to revert their VM without rebuilding it 96 | qemu-img snapshot -c initial "$IMG_FILE" 97 | 98 | echo "Successfully created $IMG_FILE!" 99 | -------------------------------------------------------------------------------- /get_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Downloads a stock kernel from Xilinx's wiki. It's not perfect, but it gets the 4 | # job done. 5 | # 6 | 7 | cd `dirname $0` 8 | 9 | [ -d linux ] || mkdir linux 10 | pushd linux 11 | 12 | wget -c https://xilinx-wiki.atlassian.net/wiki/download/attachments/18841788/2016.2-zed-release.tar.xz 13 | 14 | [ ! -f uImage ] || rm uImage 15 | [ ! -f devicetree.dtb ] || rm devicetree.dtb 16 | 17 | tar -xf 2016.2-zed-release.tar.xz --strip=1 zed/uImage 18 | tar -xf 2016.2-zed-release.tar.xz --strip=1 zed/devicetree.dtb 19 | 20 | echo "Success!" 21 | 22 | popd 23 | -------------------------------------------------------------------------------- /params: -------------------------------------------------------------------------------- 1 | 2 | IMG_FILE="roborio.img" 3 | 4 | RAM_SIZE="1024" # in MB 5 | HDD_SIZE="20G" 6 | 7 | LOCAL_SSH_PORT=10022 8 | -------------------------------------------------------------------------------- /reset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Resetting RobotRIO VM image back to initial state..." 4 | 5 | read -r -p "Are you sure? [y/N] " response 6 | case $response in 7 | [yY][eE][sS]|[yY]) 8 | qemu-img snapshot -a initial roborio.img 9 | echo "RoboRIO VM image restored to initial state" 10 | ;; 11 | *) 12 | do_something_else 13 | ;; 14 | esac 15 | -------------------------------------------------------------------------------- /run_vm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | cd `dirname $0` 4 | source params 5 | 6 | if [ ! -f linux/uImage ]; then 7 | echo "Cannot find kernel, run ./get_linux.sh first!" 8 | exit 1 9 | fi 10 | 11 | qemu-system-arm \ 12 | -machine xilinx-zynq-a9 -cpu cortex-a9 -m $RAM_SIZE \ 13 | -kernel linux/uImage -dtb linux/devicetree.dtb \ 14 | -display none -serial null -serial mon:stdio \ 15 | -localtime \ 16 | -append "console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0 rw" \ 17 | -net user,hostfwd=tcp::${LOCAL_SSH_PORT}-:22 \ 18 | -net nic \ 19 | -sd "$IMG_FILE" 20 | 21 | # TODO: how to safely shutdown the system? 22 | --------------------------------------------------------------------------------