#pypp 0 // Iris: micro-kernel for a capability-based operating system. // mips/nanonote/nanonote-boot.ccp: Host-side helper for booting over USB. // Copyright 2009 Bas Wijnen // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include #include #include asm volatile (".section .rodata\n" ".globl stage1\n" ".globl stage1_end\n" "stage1:\n" ".incbin \"mips/nanonote/sdram-setup.raw\"\n" "stage1_end:\n" ".section .text") extern char stage1[1] extern char stage1_end[1] unsigned const stage1_load = 0x80002000 unsigned const stage1_start = 0x80002000 unsigned const stage1_size = stage1_end - stage1 class nanonote: public: nanonote (unsigned skip = 0) void boot (std::string const &data, unsigned load, unsigned start) private: enum requests: VR_GET_CPU_INFO = 0 VR_SET_DATA_ADDRESS = 1 VR_SET_DATA_LENGTH = 2 VR_FLUSH_CACHES = 3 VR_PROGRAM_START1 = 4 VR_PROGRAM_START2 = 5 static int const vendor = 0x601a static int const product = 0x4740 static unsigned const timeout = 1000 usb_dev_handle *handle int interface int in_ep, out_ep std::string cpu_info bool try_open (struct usb_device *dev) bool find_device (unsigned skip) void request (requests num, unsigned data = 0) void send_file (unsigned address, unsigned size, char const *data) void get_cpu_info () bool nanonote::try_open (struct usb_device *dev): handle = usb_open (dev) if dev->descriptor.bNumConfigurations != 1: usb_close (handle) std::cerr << dev->descriptor.bNumConfigurations << " configurations\n" return false if usb_set_configuration (handle, 1) < 0: usb_close (handle) std::cerr << "Can't set configuration 1: " << usb_strerror () << '\n' return false interface = dev->config->interface->altsetting->bInterfaceNumber bool have_in = false, have_out = false for unsigned i = 0; i < dev->config->interface->altsetting->bNumEndpoints; ++i: if (dev->config->interface->altsetting->endpoint[i].bmAttributes & USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_BULK: usb_close (handle) std::cerr << "Device has non-bulk endpoint.\n" return false if (dev->config->interface->altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK): /* input */ if have_in: usb_close (handle) std::cerr << "Device has multiple IN endpoints.\n" return false have_in = true in_ep = dev->config->interface->altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK if in_ep != 1: usb_close (handle) std::cerr << "IN endpoint is not numbered as 1.\n" return false else: /* output */ if have_out: usb_close (handle) std::cerr << "Device has multiple OUT endpoints.\n" return false have_out = true out_ep = dev->config->interface->altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK if out_ep != 1: usb_close (handle) std::cerr << "OUT endpoint is not numbered as 1.\n" return false if usb_claim_interface (handle, interface) < 0: std::cerr << "unable to claim interface\n" return false return true bool nanonote::find_device (unsigned skip): unsigned skipped = 0 usb_init () usb_find_busses () usb_find_devices () for struct usb_bus *bus = usb_busses; bus; bus = bus->next: for struct usb_device *dev = bus->devices; dev; dev = dev->next: if dev->descriptor.idProduct != product || dev->descriptor.idVendor != vendor: continue if skip > skipped++: continue if try_open (dev): return true return false nanonote::nanonote (unsigned skip): if !find_device (skip): std::cerr << "unable to find NanoNote device.\n"; throw "unable to find NanoNote device"; void nanonote::get_cpu_info (): char buffer[8] if usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, VR_GET_CPU_INFO, 0, 0, buffer, 8, timeout) < 0: std::cerr << "unable to request cpu info from NanoNote: " << usb_strerror () << ".\n" throw "unable to request cpu info from NanoNote" cpu_info = std::string (buffer, 8) void nanonote::request (requests r, unsigned data): std::cerr << "requesting " << r << " (data = " << std::hex << data << ")" << std::endl if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, r, (data >> 16) & 0xffff, data & 0xffff, NULL, 0, timeout) < 0: std::cerr << "unable to send control message to NanoNote: " << usb_strerror () << ".\n" throw "unable to send control message to NanoNote" void nanonote::send_file (unsigned address, unsigned size, char const *data): request (VR_SET_DATA_ADDRESS, address) //request (VR_SET_DATA_LENGTH, size) char const *ptr = data while ptr - data < size: int ret = usb_bulk_write (handle, out_ep, ptr, size - (ptr - data), timeout) if ret <= 0: std::cerr << "failed to write to NanoNote.\n" throw "failed to write to NanoNote" ptr += ret void nanonote::boot (std::string const &data, unsigned load, unsigned start): get_cpu_info () std::cerr << "info: " << cpu_info << std::endl send_file (stage1_load, stage1_size, stage1) request (VR_PROGRAM_START1, stage1_start) usleep (100) send_file (load, data.size (), data.data ()) request (VR_FLUSH_CACHES) request (VR_PROGRAM_START2, start) sleep (1) get_cpu_info () std::cerr << "info: "; for unsigned i = 0; i < cpu_info.size (); ++i: std::cerr << std::setfill ('0') << std::setw (2) << std::hex << (cpu_info[i] & 0xff); std::cerr << std::endl int main (int argc, char **argv): if argc != 3: std::cerr << "Usage: " << argv[0] << " [kernel] [entry address]\n" std::cerr << "The kernel is loaded from 0x80000000 and run from entry address\n" return 1 unsigned entry = strtoul (argv[2], NULL, 0) nanonote nn std::ifstream file (argv[1]) if !file: std::cerr << "can't open file '" << argv[1] << "' for reading.\n" return 1 std::ostringstream data data << file.rdbuf () if data.str ().empty (): std::cerr << "no data read from '" << argv[1] << "'.\n" return 1 nn.boot (data.str (), 0x80000000, entry) return 0