#pypp 0 // Iris: micro-kernel for a capability-based operating system. // boot-programs/nand.ccp: NAND driver. // 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 "devices.hh" #define ARCH #include "arch.hh" #define debug Iris::debug #define DELAY Iris::schedule #include "nand.hh" #undef debug static unsigned *cache static bool dirty static unsigned current_block static void sync (): //Iris::debug ("erasing %x\n", current_block << block_bits) erase (current_block << block_bits) for unsigned p = 0; p < 1 << (block_bits - page_bits); ++p: write ((current_block << block_bits) + (p << page_bits), (char *)&cache[p << (page_bits - 2)]) static void read_block (unsigned b): if b == current_block: return if current_block != ~0 && dirty: sync () current_block = b //kdebug ("setting current block to ") //kdebug_num (b) //kdebug ("\n") for unsigned p = 0; p < 1 << (block_bits - 9); ++p: read ((b << block_bits) + (p << 9), (char *)&cache[p << (9 - 2)]) dirty = false Iris::Num start (): map_emc () map_gpio () // Arbitrary addresses where the pages are mapped. command = (volatile char *)0x15000 address = (volatile char *)0x16000 data = (volatile char *)0x17000 Iris::Page data_page = Iris::my_memory.create_page () Iris::Page command_page = Iris::my_memory.create_page () Iris::Page address_page = Iris::my_memory.create_page () unsigned base = 0x18000000 data_page.alloc_physical (base, false, false) command_page.alloc_physical (base + 0x8000, false, false) address_page.alloc_physical (base + 0x10000, false, false) Iris::my_memory.map (data_page, (unsigned)data) Iris::my_memory.map (command_page, (unsigned)command) Iris::my_memory.map (address_page, (unsigned)address) Iris::free_cap (data_page) Iris::free_cap (command_page) Iris::free_cap (address_page) reset () current_block = ~0 dirty = false cache = (unsigned *)0x40000000 for unsigned p = 0; p < 1 << (block_bits - PAGE_BITS); ++p: Iris::Page page = Iris::my_memory.create_page () page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) Iris::my_memory.map (page, (unsigned)cache + (p << PAGE_BITS)) Iris::free_cap (page) Iris::Page tmp = Iris::my_memory.create_page () tmp.set_flags (Iris::Page::PAYING) unsigned *tmp_addr = (unsigned *)0x3ffff000 Iris::my_memory.map (tmp, (unsigned)tmp_addr) Iris::Cap cap = Iris::my_receiver.create_capability (0) Iris::my_parent.provide_capability (cap.copy ()) Iris::free_cap (cap) Iris::my_parent.init_done () while true: Iris::wait () switch Iris::recv.data[0].l: case Iris::Block::GET_SIZE: if size_bits > 32: Iris::recv.reply.invoke (Iris::Num (0, 1 << (size_bits - 32))) else: Iris::recv.reply.invoke (1 << size_bits) break case Iris::Block::GET_ALIGN_BITS: Iris::recv.reply.invoke (9) break case Iris::Block::GET_BLOCK: unsigned row = Iris::recv.data[1].value () >> 9 unsigned block = row >> (block_bits - 9) row &= (1 << (block_bits - 9)) - 1 unsigned offset = Iris::recv.data[0].h & 0xe00 unsigned size = Iris::recv.data[0].h >> 16 if size + offset >= 0x1000: size = 0x1000 - offset #if 0 kdebug ("get ") kdebug_num (block) kdebug (":") kdebug_num (row) kdebug ("+") kdebug_num (size) kdebug ("@") kdebug_num (offset) kdebug ("\n") #endif read_block (block) Iris::Cap reply = Iris::get_reply () Iris::Page page = Iris::get_arg () page.share (tmp) tmp.set_flags (Iris::Page::FRAME) for unsigned t = 0; t < size >> 2; ++t: tmp_addr[(offset >> 2) + t] = cache[t + (row << (9 - 2))] tmp.set_flags (0, Iris::Page::FRAME) reply.invoke () Iris::free_cap (reply) Iris::free_cap (page) break case Iris::WBlock::SET_BLOCK: unsigned row = Iris::recv.data[1].value () >> 9 unsigned block = row >> (block_bits - 9) row &= (1 << (block_bits - 9)) - 1 unsigned offset = Iris::recv.data[0].h & 0xe00 unsigned size = Iris::recv.data[0].h >> 16 if size + offset >= 0x1000: size = 0x1000 - offset #if 0 kdebug ("set ") kdebug_num (block) kdebug (":") kdebug_num (row) kdebug ("+") kdebug_num (size) kdebug ("@") kdebug_num (offset) kdebug ("\n") #endif //kdebug_num (current_block) //kdebug ("/") read_block (block) Iris::Cap reply = Iris::get_reply () Iris::Page page = Iris::get_arg () page.share (tmp) tmp.set_flags (Iris::Page::FRAME) for unsigned t = 0; t < size; t += 4: cache[(offset + t + (row << 9)) >> 2] = tmp_addr[(offset + t) >> 2] tmp.set_flags (0, Iris::Page::FRAME) reply.invoke () Iris::free_cap (reply) Iris::free_cap (page) dirty = true //kdebug_num (current_block) //kdebug ("!") break case Iris::WBlock::TRUNCATE: default: Iris::recv.reply.invoke (Iris::ERR_INVALID_OPERATION) break