2009-09-27 11:23:33 +03:00
|
|
|
#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 <wijnen@debian.org>
|
|
|
|
//
|
|
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <usb.h>
|
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
2009-09-30 00:48:33 +03:00
|
|
|
#include <iomanip>
|
2009-09-27 11:23:33 +03:00
|
|
|
|
|
|
|
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
|
2009-09-27 22:14:38 +03:00
|
|
|
bool have_in = false, have_out = false
|
2009-09-27 11:23:33 +03:00
|
|
|
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
|
2009-09-27 22:14:38 +03:00
|
|
|
have_in = true
|
2009-09-27 11:23:33 +03:00
|
|
|
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
|
2009-09-27 22:14:38 +03:00
|
|
|
have_out = true
|
2009-09-27 11:23:33 +03:00
|
|
|
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";
|
2009-10-04 20:47:20 +03:00
|
|
|
// Get info will reset the device if it has already booted into Iris.
|
|
|
|
get_cpu_info ()
|
|
|
|
usb_close (handle)
|
|
|
|
sleep (1)
|
|
|
|
if !find_device (skip):
|
|
|
|
std::cerr << "unable to find NanoNote device again.\n";
|
|
|
|
throw "unable to find NanoNote device again";
|
2009-09-27 11:23:33 +03:00
|
|
|
|
|
|
|
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):
|
|
|
|
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)
|
|
|
|
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):
|
|
|
|
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)
|
|
|
|
|
|
|
|
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
|