Root/
| 1 | #pypp 0 |
| 2 | // Iris: micro-kernel for a capability-based operating system. |
| 3 | // mips/nanonote/nanonote-boot.ccp: Host-side helper for booting over USB. |
| 4 | // Copyright 2009 Bas Wijnen <wijnen@debian.org> |
| 5 | // |
| 6 | // This program is free software: you can redistribute it and/or modify |
| 7 | // it under the terms of the GNU General Public License as published by |
| 8 | // the Free Software Foundation, either version 3 of the License, or |
| 9 | // (at your option) any later version. |
| 10 | // |
| 11 | // This program is distributed in the hope that it will be useful, |
| 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | // GNU General Public License for more details. |
| 15 | // |
| 16 | // You should have received a copy of the GNU General Public License |
| 17 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | |
| 19 | #include <unistd.h> |
| 20 | #include <usb.h> |
| 21 | #include <fstream> |
| 22 | #include <sstream> |
| 23 | #include <iostream> |
| 24 | #include <iomanip> |
| 25 | |
| 26 | asm volatile (".section .rodata\n" |
| 27 | ".globl stage1\n" |
| 28 | ".globl stage1_end\n" |
| 29 | "stage1:\n" |
| 30 | ".incbin \"mips/nanonote/stage1.raw\"\n" |
| 31 | "stage1_end:\n" |
| 32 | ".section .text") |
| 33 | extern char stage1[1] |
| 34 | extern char stage1_end[1] |
| 35 | |
| 36 | unsigned const stage1_load = 0x80003000 |
| 37 | unsigned const stage1_start = 0x80003000 |
| 38 | unsigned const stage1_size = stage1_end - stage1 |
| 39 | |
| 40 | class nanonote: |
| 41 | public: |
| 42 | |
| 43 | nanonote (unsigned skip = 0) |
| 44 | void boot (std::string const &data, unsigned load, unsigned start) |
| 45 | |
| 46 | private: |
| 47 | |
| 48 | enum requests: |
| 49 | VR_GET_CPU_INFO = 0 |
| 50 | VR_SET_DATA_ADDRESS = 1 |
| 51 | VR_SET_DATA_LENGTH = 2 |
| 52 | VR_FLUSH_CACHES = 3 |
| 53 | VR_PROGRAM_START1 = 4 |
| 54 | VR_PROGRAM_START2 = 5 |
| 55 | static int const vendor = 0x601a |
| 56 | static int const product = 0x4740 |
| 57 | static unsigned const timeout = 1000 |
| 58 | usb_dev_handle *handle |
| 59 | int interface |
| 60 | int in_ep, out_ep |
| 61 | std::string cpu_info |
| 62 | bool try_open (struct usb_device *dev) |
| 63 | bool find_device (unsigned skip) |
| 64 | void request (requests num, unsigned data = 0) |
| 65 | void send_file (unsigned address, unsigned size, char const *data) |
| 66 | void get_cpu_info () |
| 67 | |
| 68 | bool nanonote::try_open (struct usb_device *dev): |
| 69 | handle = usb_open (dev) |
| 70 | |
| 71 | if dev->descriptor.bNumConfigurations != 1: |
| 72 | usb_close (handle) |
| 73 | std::cerr << dev->descriptor.bNumConfigurations << " configurations\n" |
| 74 | return false |
| 75 | if usb_set_configuration (handle, 1) < 0: |
| 76 | usb_close (handle) |
| 77 | std::cerr << "Can't set configuration 1: " << usb_strerror () << '\n' |
| 78 | return false |
| 79 | |
| 80 | interface = dev->config->interface->altsetting->bInterfaceNumber |
| 81 | bool have_in = false, have_out = false |
| 82 | for unsigned i = 0; i < dev->config->interface->altsetting->bNumEndpoints; ++i: |
| 83 | if (dev->config->interface->altsetting->endpoint[i].bmAttributes & USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_BULK: |
| 84 | usb_close (handle) |
| 85 | std::cerr << "Device has non-bulk endpoint.\n" |
| 86 | return false |
| 87 | if (dev->config->interface->altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK): |
| 88 | /* input */ |
| 89 | if have_in: |
| 90 | usb_close (handle) |
| 91 | std::cerr << "Device has multiple IN endpoints.\n" |
| 92 | return false |
| 93 | have_in = true |
| 94 | in_ep = dev->config->interface->altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK |
| 95 | if in_ep != 1: |
| 96 | usb_close (handle) |
| 97 | std::cerr << "IN endpoint is not numbered as 1.\n" |
| 98 | return false |
| 99 | else: |
| 100 | /* output */ |
| 101 | if have_out: |
| 102 | usb_close (handle) |
| 103 | std::cerr << "Device has multiple OUT endpoints.\n" |
| 104 | return false |
| 105 | have_out = true |
| 106 | out_ep = dev->config->interface->altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK |
| 107 | if out_ep != 1: |
| 108 | usb_close (handle) |
| 109 | std::cerr << "OUT endpoint is not numbered as 1.\n" |
| 110 | return false |
| 111 | if usb_claim_interface (handle, interface) < 0: |
| 112 | std::cerr << "unable to claim interface\n" |
| 113 | return false |
| 114 | return true |
| 115 | |
| 116 | bool nanonote::find_device (unsigned skip): |
| 117 | unsigned skipped = 0 |
| 118 | usb_init () |
| 119 | usb_find_busses () |
| 120 | usb_find_devices () |
| 121 | for struct usb_bus *bus = usb_busses; bus; bus = bus->next: |
| 122 | for struct usb_device *dev = bus->devices; dev; dev = dev->next: |
| 123 | if dev->descriptor.idProduct != product || dev->descriptor.idVendor != vendor: |
| 124 | continue |
| 125 | if skip > skipped++: |
| 126 | continue |
| 127 | if try_open (dev): |
| 128 | return true |
| 129 | return false |
| 130 | |
| 131 | nanonote::nanonote (unsigned skip): |
| 132 | if !find_device (skip): |
| 133 | std::cerr << "unable to find NanoNote device.\n"; |
| 134 | throw "unable to find NanoNote device"; |
| 135 | // Get info will reset the device if it has already booted into Iris. |
| 136 | get_cpu_info () |
| 137 | usb_close (handle) |
| 138 | sleep (5) |
| 139 | if !find_device (skip): |
| 140 | std::cerr << "unable to find NanoNote device again.\n"; |
| 141 | throw "unable to find NanoNote device again"; |
| 142 | |
| 143 | void nanonote::get_cpu_info (): |
| 144 | char buffer[8] |
| 145 | if usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, VR_GET_CPU_INFO, 0, 0, buffer, 8, timeout) < 0: |
| 146 | std::cerr << "unable to request cpu info from NanoNote: " << usb_strerror () << ".\n" |
| 147 | throw "unable to request cpu info from NanoNote" |
| 148 | cpu_info = std::string (buffer, 8) |
| 149 | |
| 150 | void nanonote::request (requests r, unsigned data): |
| 151 | if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, r, (data >> 16) & 0xffff, data & 0xffff, NULL, 0, timeout) < 0: |
| 152 | std::cerr << "unable to send control message to NanoNote: " << usb_strerror () << ".\n" |
| 153 | throw "unable to send control message to NanoNote" |
| 154 | |
| 155 | void nanonote::send_file (unsigned address, unsigned size, char const *data): |
| 156 | request (VR_SET_DATA_ADDRESS, address) |
| 157 | char const *ptr = data |
| 158 | while ptr - data < size: |
| 159 | int ret = usb_bulk_write (handle, out_ep, ptr, size - (ptr - data), timeout) |
| 160 | if ret <= 0: |
| 161 | std::cerr << "failed to write to NanoNote.\n" |
| 162 | throw "failed to write to NanoNote" |
| 163 | ptr += ret |
| 164 | |
| 165 | void nanonote::boot (std::string const &data, unsigned load, unsigned start): |
| 166 | send_file (stage1_load, stage1_size, stage1) |
| 167 | request (VR_PROGRAM_START1, stage1_start) |
| 168 | usleep (100) |
| 169 | send_file (load, data.size (), data.data ()) |
| 170 | request (VR_FLUSH_CACHES) |
| 171 | request (VR_PROGRAM_START2, start) |
| 172 | |
| 173 | int main (int argc, char **argv): |
| 174 | if argc != 3: |
| 175 | std::cerr << "Usage: " << argv[0] << " [kernel] [entry address]\n" |
| 176 | std::cerr << "The kernel is loaded from 0x80000000 and run from entry address\n" |
| 177 | return 1 |
| 178 | unsigned entry = strtoul (argv[2], NULL, 0) |
| 179 | nanonote nn |
| 180 | std::ifstream file (argv[1]) |
| 181 | if !file: |
| 182 | std::cerr << "can't open file '" << argv[1] << "' for reading.\n" |
| 183 | return 1 |
| 184 | std::ostringstream data |
| 185 | data << file.rdbuf () |
| 186 | if data.str ().empty (): |
| 187 | std::cerr << "no data read from '" << argv[1] << "'.\n" |
| 188 | return 1 |
| 189 | nn.boot (data.str (), 0x80000000, entry) |
| 190 | return 0 |
| 191 |
Branches:
master
