Root/mips/nanonote/nanonote-boot.ccp

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
26asm 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")
33extern char stage1[1]
34extern char stage1_end[1]
35
36unsigned const stage1_load = 0x80003000
37unsigned const stage1_start = 0x80003000
38unsigned const stage1_size = stage1_end - stage1
39
40class 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
68bool 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
116bool 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
131nanonote::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
143void 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
150void 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
155void 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
165void 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
173int 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

Archive Download this file

Branches:
master



interactive