1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-06-26 02:37:17 +03:00

working fat system on sd card

This commit is contained in:
Bas Wijnen 2010-06-06 23:03:25 +02:00
parent 6bf41032d8
commit 8968030551
26 changed files with 1343 additions and 272 deletions

View File

@ -23,7 +23,7 @@ CC = $(CROSS)gcc
LD = $(CROSS)ld
OBJCOPY = $(CROSS)objcopy
headers = kernel.hh iris.hh devices.hh ui.hh $(arch_headers)
headers = kernel.hh iris.hh devices.hh ui.hh keys.hh $(arch_headers)
iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
BUILT_SOURCES = $(iris_sources) $(boot_sources)

View File

@ -1,147 +0,0 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/init.S: Startup code for initial Threads.
// 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 "iris.hh"
#include "devices.hh"
// For some unknown reason, gcc needs this to be defined.
unsigned __gxx_personality_v0
struct list:
list *prev, *next
static unsigned __slots, __caps
static list *__slot_admin, *__cap_admin
static list *__first_free_slot, *__first_free_cap
namespace Iris:
Caps my_caps
Receiver my_receiver
Thread my_thread
Memory my_memory
Cap my_call
Parent my_parent
__recv_data_t recv
void print_caps ():
// Assume __caps to be 32.
bool used[32]
for unsigned i = 0; i < 32; ++i:
used[i] = true
unsigned num = 0
for list *i = __first_free_cap; i; i = i->next:
used[i - __cap_admin] = false
++num
kdebug_num (num, 2)
kdebug (":")
for unsigned i = 0; i < 32; ++i:
kdebug_char (used[i] ? '#' : '.')
kdebug_char ('\n')
void free_slot (unsigned slot):
//kdebug ("free slot\n")
__slot_admin[slot].prev = NULL
__slot_admin[slot].next = __first_free_slot
if __slot_admin[slot].next:
__slot_admin[slot].next->prev = &__slot_admin[slot]
__first_free_slot = &__slot_admin[slot]
void free_cap (Cap cap):
//kdebug ("free cap\n")
if cap.slot () != 0:
kdebug ("trying to free capability from non-0 slot\n")
return
list *l = &__cap_admin[cap.idx ()]
l->prev = NULL
l->next = __first_free_cap
if l->next:
l->next->prev = l
__first_free_cap = l
unsigned alloc_slot ():
//kdebug ("alloc slot\n")
if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
kdebug ("out of slots!\n")
Iris::panic (0)
return ~0
list *ret = __first_free_slot
__first_free_slot = ret->next
if ret->next:
ret->next->prev = NULL
return ret - __slot_admin
Cap alloc_cap ():
//kdebug ("alloc cap\n")
if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
kdebug ("out of capabilities!\n")
Iris::panic (0)
return Cap (0, CAP_NONE)
list *ret = __first_free_cap
__first_free_cap = ret->next
if ret->next:
ret->next->prev = NULL
return Cap (0, ret - __cap_admin)
extern "C":
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
__slots = slots
__caps = caps
__slot_admin = slot_admin
__cap_admin = cap_admin
__first_free_slot = NULL
for unsigned i = 1; i < __slots; ++i:
Iris::free_slot (i)
__first_free_cap = NULL
for unsigned i = 6; i < __caps; ++i:
Iris::free_cap (Iris::Cap (0, i))
Iris::my_caps = Iris::Cap (0, __caps_num)
Iris::my_receiver = Iris::Cap (0, __receiver_num)
Iris::my_thread = Iris::Cap (0, __thread_num)
Iris::my_memory = Iris::Cap (0, __memory_num)
Iris::my_call = Iris::Cap (0, __call_num)
Iris::my_parent = Iris::Cap (0, __parent_num)
Iris::recv.reply = Iris::alloc_cap ()
Iris::recv.arg = Iris::alloc_cap ()
Iris::Num ret = start ()
Iris::my_parent.exit (ret)
Iris::my_memory.destroy (Iris::my_thread)
// The program no longer exists. If it somehow does, generate an address fault.
while true:
*(volatile unsigned *)~0
__asm__ volatile ("\t.globl __start\n"
"\t.set noreorder\n"
"__start:\n"
"\tbal 1f\n"
"__hack_label:\n"
"\tnop\n"
"\t.word _gp\n"
"1:\n"
"\tlw $gp, 0($ra)\n"
"\tsll $v0, $a0, 3\n"
"\tsll $v1, $a1, 3\n"
"\tsubu $sp, $sp, $v0\n"
"\tmove $a2, $sp\n"
"\tsubu $sp, $sp, $v1\n"
"\tmove $a3, $sp\n"
"\tla $t9, run__main\n"
"\tjr $t9\n"
"\tnop\n"
"\t.set reorder")

View File

@ -39,12 +39,13 @@ namespace Iris:
enum request:
GET_SIZE = 0x2001
GET_CHARS
GET_PAGE
GET_ALIGN_BITS
GET_BLOCK
ID
/// Get the size of the string.
Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
/// Get exactly 16 characters. The index must be word-aligned.
/// Get exactly 16 characters. The index must be aligned to 16 bytes or align_bits, whichever is smaller.
char *get_chars (Num idx, char buffer[16]):
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
unsigned *b = (unsigned *)buffer
@ -53,14 +54,17 @@ namespace Iris:
b[2] = recv.data[1].l
b[3] = recv.data[1].h
return buffer
/// Helper function for get_page.
/// Get the number of bits that page accesses must be aligned to. Cannot be more than PAGE_BITS.
unsigned get_align_bits ():
return call (CAP_MASTER_DIRECT | GET_ALIGN_BITS).l
/// Helper function for get_block.
static Page _create_paying_page ():
Page ret = my_memory.create_page ()
ret.set_flags (Page::PAYING, Page::PAYING)
return ret
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
Cap get_page (Num idx, Page ret = _create_paying_page ()):
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
/// Get a block from the string; place it at offset on page. This need not be implemented for strings smaller than PAGE_SIZE. All arguments must be aligned.
Cap get_block (Num idx, unsigned size = PAGE_SIZE, unsigned offset = 0, Page ret = _create_paying_page ()):
ocall (ret, Iris::Num (CAP_MASTER_DIRECT | GET_BLOCK, size << 16 | offset), idx)
return ret
/// A writable String.
@ -69,7 +73,7 @@ namespace Iris:
enum request:
TRUNCATE = String::ID
SET_CHARS
SET_PAGE
SET_BLOCK
ID
/// Set the size of the string. Strings may have a limit to this setting.
void truncate (Num size):
@ -77,9 +81,9 @@ namespace Iris:
/// Set exactly 4 characters. The index must be word-aligned.
void set_chars (Num idx, char buffer[4]):
call (Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
void set_page (Num idx, Page page):
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
/// Overwrite a block from the string with data at offset on the page. This need not be implemented for strings smaller than PAGE_SIZE. The all arguments must be aligned. The caller may lose the frame in the transaction. Only the specified part of the page is used for overwriting data.
void set_block (Num idx, Page page, unsigned size = PAGE_SIZE, unsigned offset = 0):
ocall (page, Iris::Num (CAP_MASTER_DIRECT | SET_BLOCK, size << 16 | offset), idx)
// Every process which wants to be switchable through a terminal must implement this interface.
struct Device : public Cap:

View File

@ -1,33 +1,44 @@
# driver <name> = '<filename>' load a file into memory to be run priviledged.
# program <name> = '<filename>' load a file into memory to be run normally.
driver driver_lcd = "lcd.elf"
driver driver_buzzer = "buzzer.elf"
#driver driver_lcd = "lcd.elf"
#driver driver_buzzer = "buzzer.elf"
driver driver_gpio = "gpio.elf"
program alarm = "alarm.elf"
program gui = "gui.elf"
#program alarm = "alarm.elf"
#program gui = "gui.elf"
#driver nand = "nand.elf"
driver sdmmc = "sd+mmc.elf"
program partition = "partition.elf"
program fat = "fat.elf"
program test = "test.elf"
# receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
receive driver_lcd / Display = display
receive driver_lcd / Setting = display_bright
receive driver_buzzer / Buzzer = buzzer
#receive driver_lcd / Display = display
#receive driver_lcd / Setting = display_bright
#receive driver_buzzer / Buzzer = buzzer
receive driver_gpio / Keyboard , 0 = keyboard
receive driver_gpio / Keyboard , 1 = sysreq
receive driver_gpio / Event = sdmmc_gpio
receive alarm / UI = ui
#receive alarm / UI = ui
receive sdmmc / WString = sdmmc
receive partition / WString, 0 = p0
receive partition / WString, 1 = p1
receive partition / WString, 2 = p2
receive partition / WString, 3 = p3
receive fat / Directory = root
# sysreq <cap> use a capability as the system request keyboard.
sysreq sysreq
# give <name> / <type> [, <index>] = <cap> give this capability to this program when it requests it.
give gui / UI = ui
give gui / Display = display
give gui / Setting = display_bright
give gui / Buzzer = buzzer
give gui / Keyboard = keyboard
#give gui / UI = ui
#give gui / Display = display
#give gui / Setting = display_bright
#give gui / Buzzer = buzzer
#give gui / Keyboard = keyboard
give sdmmc / Event = sdmmc_gpio
give partition / WString = sdmmc
give fat / WString = p0
give test / Directory = root
# include <file> include a file as another config file.

View File

@ -233,6 +233,9 @@ static void receiver_invoke (unsigned cmd, unsigned target, Iris::Num protected_
return
case Iris::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK:
receiver->reply_protected_data = c->data[1]
// Adjust target protected data, so the reply will reach the caller.
if receiver == reply_target:
reply_protected = receiver->reply_protected_data
break
case Iris::Receiver::GET_ALARM & REQUEST_MASK:
reply_num (receiver->alarm_count)
@ -701,6 +704,9 @@ static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data
t->flags |= Iris::Page::FRAME
kPage_arch_update_mapping (t)
break
case Iris::Page::GET_FLAGS & REQUEST_MASK:
reply_num (page->flags)
return
case Iris::Page::SET_FLAGS & REQUEST_MASK:
if cmd & Iris::Page::READONLY:
dpanic (0, "setting page flags denied")
@ -989,7 +995,6 @@ static void kernel_invoke (unsigned target, Iris::Num protected_data, kCapabilit
c->reply.reset ()
reply_target = (kReceiver *)protected_data.l
reply_protected = reply_target->reply_protected_data
kReceiver *r = reply_target
kernel_invoke ((unsigned)call_target->target, call_target->protected_data, c)
return
if must_wait:

View File

@ -294,7 +294,7 @@ namespace Iris:
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
void set_alarm (unsigned data):
call (CAP_MASTER_DIRECT | SET_ALARM, data)
static inline void sleep (unsigned value)
inline void sleep (unsigned value)
Cap create_call_capability ():
icall (CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
return get_arg ()
@ -567,6 +567,10 @@ namespace Iris:
my_thread.ocall (my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
inline void unregister_interrupt (unsigned num):
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
inline void wait_for_interrupt (unsigned num):
my_receiver.set_reply_protected_data (num)
Cap ().call ()
my_receiver.set_reply_protected_data (~0)
inline Cap get_top_memory ():
my_thread.icall (CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
return get_arg ()
@ -576,8 +580,10 @@ namespace Iris:
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT)
void Receiver::sleep (unsigned value):
my_receiver.set_alarm (value)
set_alarm (value)
Cap ().call ()
inline void sleep (unsigned value):
my_receiver.sleep (value)
// The start function has this prototype (there is no main function).
Iris::Num start ()

View File

@ -122,7 +122,7 @@ struct kThread : public kObject:
unsigned flags
kThreadP schedule_prev, schedule_next
unsigned recv_reply, recv_arg
// caps is an array of slots pointers to kCapses.
// slot[] is an array of slots pointers to kCapses.
unsigned slots
#ifndef NDEBUG
unsigned id

88
mbr+fat.txt Normal file
View File

@ -0,0 +1,88 @@
mbr structure. Size: 200.
000 1b8 code or fat:
00 3 jump instruction
03 8 OEM name
0b 2 bytes per sector
0d 1 sectors per cluster
0e 2 reserved sectors (incl. boot sector, from boot sector)
10 1 number of fats
11 2 non fat32: number of entries in root directory
13 2 total number of sectors on disk if < 32MB
15 1 media descriptor (bit 2 set means removable)
16 2 non fat32: sectors per fat
18 2 sectors per track
1a 2 heads
1c 4 number of sectors before boot sector
20 4 number of sectors on disk, if > 32MB
24 xx 4 sectors per fat
28 xx 2 bit 0-4: active fat, bit 7 set: write to all fats.
2a xx 2 file system version number
2c xx 4 cluster number for root directory
30 xx 2 sector number for FSInfo structure
32 xx 2 boot sector backup sector
34 xx c reserved
40 24 1 drive number
41 25 1 current head (dos internal)
42 26 1 boot signature (with 0x29, the next 3 fields are valid)
43 27 4 volume id
47 2b b volume label
52 36 8 file system type "FAT16 " / "FAT32 " / ...
1b8 004 disk signature
1bc 002 null
1be 010 partition 0
1ce 010 partition 1
1de 010 partition 2
1ee 010 partition 3
1fe 002 mbr signature: 55 aa.
Partition structure. Size: 10.
0 1 bootable flag 00=no; 80=yes.
1 3 first sector in partition, chs
4 1 partition type
5 3 last sector in partition, chs
8 4 first sector in partition, lba
c 4 number of sectors in partition, for lba
CHS address. Size: 3.
head = chs[0]
sector = chs[1] & 0x3f
cylinder = (chs[1] & 0xc0) << 2 | chs[2]
Fat filesystem information sector. Size: 200.
000 4 signature: 52 52 61 41
004 1e0 unused
1e4 4 fsinfo signature: 72 72 41 61
1e8 4 number of free clusters
1ec 4 most recently allocated cluster
1f0 c reserved
1fc 2 unknown
1fe 2 boot record signature: 55 aa
Directory entry. Size: 20.
00 8 name
08 3 extension
0b 1 attributes (00arshdv)
0c 1 0
0d 1 creation time: (milli?)seconds
0e 2 creation time: hour and minute
10 2 creation date
12 2 last accessed date
14 2 cluster[31:16]
16 2 time
18 2 date
1a 2 cluster[15:0]
1c 4 file size
long file name: stored in directory entries immediately before the 8.3 name (last entry is first part of name)
00 1 ordinal field, bit 6 set means highest.
01 a 5 unicode characters.
0b 1 attribute: 000rsh0v.
0c 1 0
0d 1 checksum
0e c 6 unicode characters.
1a 2 0
1c 4 2 unicode characters.

View File

@ -279,6 +279,15 @@ void arch_register_interrupt (unsigned num, kReceiver *r):
arch_interrupt_receiver[num] = r
// And enable or disable the interrupt.
if r:
//if num != 0x18:
//kdebug ("enabled interrupt ")
//kdebug_num (num)
//kdebug (", state: ")
//kdebug_num (INTC_ISR)
//kdebug ("\n")
intc_unmask_irq (num)
else:
//kdebug ("disabled interrupt ")
//kdebug_num (num)
//kdebug ("\n")
intc_mask_irq (num)

View File

@ -57,6 +57,9 @@ static void init_idle ():
idle_page.address_space = NULL
current = &idle
directory = idle_memory.arch.directory
kdebug ("idle thread is ")
kdebug_num ((unsigned)&idle)
kdebug ("\n")
static void init_cp0 ():
// Disable watchpoint interrupts.
@ -116,12 +119,14 @@ static void init_threads ():
first_alarm = NULL
kReceiver *init_receiver = NULL
for unsigned i = 0; i < NUM_THREADS; ++i:
kdebug ("Starting thread ")
kdebug_num (i, 2)
kdebug ("\n")
kMemory *mem = top_memory.alloc_memory ()
assert (mem)
kThread *thread = mem->alloc_thread (NUM_SLOTS)
kdebug ("Starting thread ")
kdebug_num (i, 2)
kdebug (" at ")
kdebug_num ((unsigned)thread)
kdebug ("\n")
#ifndef NDEBUG
thread->id = i
#endif

View File

@ -111,6 +111,10 @@ kThread *interrupt ():
// Handle timer interrupts specially: don't disable them.
if i == TIMER_INTERRUPT:
continue
//if i != 0x18:
//kdebug ("interrupt: ")
//kdebug_num (i, 2)
//kdebug ("\n")
// Disable the interrupt while handling it.
intc_mask_irq (i)
intc_ack_irq (i)
@ -236,6 +240,9 @@ kThread *exception ():
current->pc += 4
#endif
#else
unsigned opcode = *(unsigned *)current->pc
if opcode == 0x0007000d:
panic (0, "Division by zero (detected by compiler)")
current->pc += 4
if current->arch.a[0]:
if dbg_cap.valid ():

View File

@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
load = 0x80000000
UDC_BOOT=1
ARCH_CXXFLAGS = -DNUM_THREADS=2
ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
@ -28,8 +29,19 @@ LDFLAGS = --omagic -Ttext $(load)
arch_iris_sources = mips/interrupts.cc mips/arch.cc
boot_sources = mips/init.cc mips/nanonote/board.cc
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
boot_threads = bootinit udc
programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm gui nand sd+mmc
udc_boot_programs = udc
sd_boot_programs = sd+mmc partition fat
standard_boot_programs = bootinit
ifdef UDC_BOOT
boot_threads = $(standard_boot_programs) $(udc_boot_programs)
threadlist = mips/nanonote/threadlist-udc
INIT_FLAGS = -DUDC_BOOT
else
boot_threads = $(standard_boot_programs) $(sd_boot_programs)
threadlist = mips/nanonote/threadlist-sd
INIT_FLAGS = -DSD_BOOT
endif
programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm gui nand test $(udc_boot_programs) $(sd_boot_programs) $(standard_boot_programs)
all: test
@ -52,17 +64,16 @@ nanonote-boot: mips/nanonote/nanonote-boot.cc mips/nanonote/sdram-setup.raw
mips/nanonote/sdram-setup.elf: mips/nanonote/sdram-setup.ld
mips/nanonote/sdram-setup.elf: LDFLAGS = --omagic -T mips/nanonote/sdram-setup.ld
mips/nanonote/threadlist.o: $(addsuffix .elf,$(boot_threads))
$(threadlist).o: $(addprefix fs/,$(addsuffix .elf,$(boot_threads)))
mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
mips/init.o: TARGET_FLAGS = -I/usr/include
boot-programs/bootinit.o: TARGET_FLAGS = -I/usr/include
mips/init.o: TARGET_FLAGS = -I/usr/include $(INIT_FLAGS)
source/bootinit.o: TARGET_FLAGS = -I/usr/include
source/elfrun.o: TARGET_FLAGS = -I/usr/include
source/gpio.ccp: source/nanonote-gpio.ccp
ln -s $(subst source/,,$<) $@
$(addsuffix .elf,$(boot_threads)): TARGET_FLAGS = -I.
$(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL
$(addprefix fs/,$(addsuffix .elf,$(boot_threads))): TARGET_FLAGS = -I.
$(addprefix fs/,$(addsuffix .elf,$(boot_threads))): LDFLAGS = -EL
$(addprefix fs/,$(addsuffix .elf,$(programs))): LDFLAGS = -EL
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh
source/lcd.o: source/charset.data
source/charset.data: source/charset
@ -72,7 +83,7 @@ source/charset.data: source/charset
$(CC) $(CPPFLAGS) $(TARGET_FLAGS) -DKERNEL_STACK_SIZE=0x2000 -c $< -o $@
# entry.o must be the first file. threadlist.o must be the first of the init objects (which can be freed after loading).
iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources))
iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) $(threadlist).o mips/boot.o $(subst .cc,.o,$(boot_sources))
$(LD) $(LDFLAGS) $^ -o $@
server:

View File

@ -163,7 +163,6 @@ void cdelay (unsigned cs):
#define IRQ_SSI 16
#define IRQ_CIM 17
#define IRQ_AIC 18
#define IRQ_ETH 19
#define IRQ_DMAC 20
#define IRQ_TCU2 21
#define IRQ_TCU1 22
@ -1227,8 +1226,6 @@ void cdelay (unsigned cs):
#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
#define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) // 1-bit data bus
#define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) // 4-bit data bus
#define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT)
#define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT)
#define MSC_CMDAT_DMA_EN (1 << 8)
#define MSC_CMDAT_INIT (1 << 7)
#define MSC_CMDAT_BUSY (1 << 6)
@ -1245,13 +1242,14 @@ void cdelay (unsigned cs):
#define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) // Format R4
#define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) // Format R5
#define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) // Format R6
#define MSC_CMDAT_RESPONSE_R7 (0x7 << MSC_CMDAT_RESPONSE_BIT) // Format R7
#define CMDAT_DMA_EN (1 << 8)
#define CMDAT_INIT (1 << 7)
#define CMDAT_BUSY (1 << 6)
#define CMDAT_STREAM (1 << 5)
#define CMDAT_WRITE (1 << 4)
#define CMDAT_DATA_EN (1 << 3)
#define MSC_CMDAT_DMA_EN (1 << 8)
#define MSC_CMDAT_INIT (1 << 7)
#define MSC_CMDAT_BUSY (1 << 6)
#define MSC_CMDAT_STREAM (1 << 5)
#define MSC_CMDAT_WRITE (1 << 4)
#define MSC_CMDAT_DATA_EN (1 << 3)
// MSC Interrupts Mask Register (MSC_IMASK)

View File

@ -156,7 +156,7 @@ void data::poll ():
if !--lock:
dir.clear ()
continue
case Iris::String::GET_PAGE:
case Iris::String::GET_BLOCK:
if buffer[1] >= dir.size ():
std::cerr << "reading invalid file" << std::endl
usb_release_interface (handle, 0)

View File

@ -0,0 +1,49 @@
// Iris: micro-kernel for a capability-based operating system.
// mips/nanonote/threadlist.S: List of initial threads.
// 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/>.
.globl init_start
.globl thread_start
.set noreorder
.balign 0x1000
thread0:
.incbin "fs/bootinit.elf"
.balign 0x1000
thread1:
.incbin "fs/sd+mmc.elf"
.balign 0x1000
thread2:
.incbin "fs/partition.elf"
.balign 0x1000
thread3:
.incbin "fs/fat.elf"
.balign 0x1000
thread4:
// Everything from here may be freed after kernel initialization.
init_start:
thread_start:
.word thread0
.word thread1
.word thread2
.word thread3
.word thread4

BIN
screen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -138,7 +138,7 @@ static void run (Iris::String data, Iris::Memory parent_memory, Iris::Cap parent
Iris::set_recv_arg (Iris::Cap (slot, p))
Iris::my_memory.create_page ()
Iris::Page (slot, p).set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
data.get_page (p << PAGE_BITS, Iris::Cap (slot, p))
data.get_block (p << PAGE_BITS, PAGE_SIZE, 0, Iris::Cap (slot, p))
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
Iris::Thread thread = mem.create_thread (NUM_SLOTS)
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping

View File

@ -139,8 +139,9 @@ extern "C":
Iris::Num ret = start ()
Iris::my_parent.exit (ret)
Iris::my_memory.destroy (Iris::my_thread)
// The program no longer exists. If it somehow does, generate an address fault.
// The program no longer exists. If it somehow does, die again.
while true:
Iris::panic (0, "this program should no longer exist.")
*(volatile unsigned *)~0
__asm__ volatile ("\t.text\n"

View File

@ -83,7 +83,7 @@ static Iris::Caps map_string (Iris::String data):
//kdebug_num (pages)
//kdebug ("\n")
Iris::set_recv_arg (Iris::Cap (slot, p))
data.get_page (p << PAGE_BITS)
data.get_block (p << PAGE_BITS)
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
static Iris::Caps map_caps (Iris::Caps data, unsigned p):

550
source/fat.ccp Normal file
View File

@ -0,0 +1,550 @@
#pypp 0
#include <iris.hh>
#include <devices.hh>
#define SECTOR_BITS 9
#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
#define ROOT_CLUSTER 0x7fffffff
static unsigned _free
extern unsigned _end
void init_alloc ():
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
char *alloc_space (unsigned pages):
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
_free = ret + (pages << PAGE_BITS)
return (char *)ret
void *operator new[] (unsigned size):
//kdebug ("new ")
void *ret = (void *)_free
size = (size + 3) & ~3
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
if rest < size:
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
for unsigned p = 0; p < pages; ++p:
Iris::Page page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
Iris::free_cap (page)
_free += size
//kdebug_num ((unsigned)ret)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("\n")
return ret
void *operator new (unsigned size):
return new char[size]
static Iris::WString dev
static Iris::Num device_size
static Iris::Page page
static char *data
static Iris::Num current_block
static void read_block (Iris::Num idx, Iris::Page p = page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
if p.code == page.code:
if idx.value () == current_block.value () && offset == 0 && size == 1 << SECTOR_BITS:
return
current_block = idx
//kdebug ("fat getting block: ")
//kdebug_num (idx.h)
//kdebug (":")
//kdebug_num (idx.l)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("@")
//kdebug_num (offset)
//kdebug ("\n")
dev.get_block (idx, size, offset, p)
struct Fat:
char oem[8]
unsigned sector_size_bits
unsigned sectors_per_cluster_bits
unsigned reserved_sectors
unsigned num_fats
unsigned root_entries
unsigned sectors
unsigned media
unsigned sectors_per_fat
unsigned sectors_per_track
unsigned heads
unsigned hidden_sectors
unsigned active_fat
bool write_all_fats
unsigned fs_version
unsigned root_cluster
unsigned fsinfo_sector
unsigned boot_backup_sector
unsigned drive
unsigned current_head
unsigned volume_id
char label[0xb]
unsigned bits
unsigned clusters
unsigned cluster_size_bits
unsigned root_sectors
unsigned header_sectors
unsigned bad_clusters
unsigned free_clusters
unsigned last_alloced
unsigned *fat
unsigned first_free_cluster, first_bad_cluster
void print_num (char const *pre, unsigned data):
kdebug ("\t")
kdebug (pre)
unsigned bytes = 1
while bytes < 8 && data >> (bytes * 4):
++bytes
kdebug_num (data, bytes)
kdebug ("\n")
void print_br ():
kdebug ("\tOEM: '")
for unsigned i = 0; i < 8; ++i:
kdebug_char (oem[i])
kdebug ("'\n")
print_num ("bytes per sector: ", 1 << sector_size_bits)
print_num ("sectors per cluster: ", 1 << sectors_per_cluster_bits)
print_num ("reserved sectors: ", reserved_sectors)
print_num ("number of fats: ", num_fats)
print_num ("entries in root directory: ", root_entries)
print_num ("sectors: ", sectors)
print_num ("media descriptor: ", media)
print_num ("sectors per fat: ", sectors_per_fat)
print_num ("sectors per track: ", sectors_per_track)
print_num ("heads: ", heads)
print_num ("hidden sectors: ", hidden_sectors)
print_num ("active_fat: ", active_fat)
kdebug ("\twrite all: ")
kdebug (write_all_fats ? "yes\n" : "no\n")
print_num ("fs version: ", fs_version)
print_num ("root cluster: ", root_cluster)
print_num ("fsinfo sector: ", fsinfo_sector)
print_num ("boot sector backup sector: ", boot_backup_sector)
print_num ("drive: ", drive)
print_num ("current head: ", current_head)
print_num ("volume id: ", volume_id)
kdebug ("\tlabel: '")
for unsigned i = 0; i < 0xb; ++i:
kdebug_char (label[i])
kdebug ("'\n")
print_num ("bits: ", bits)
print_num ("clusters: ", clusters)
print_num ("header sectors: ", header_sectors)
unsigned read_num (char *data, unsigned bytes):
unsigned ret = 0
for unsigned i = 0; i < bytes; ++i:
ret |= (data[i] & 0xff) << (i * 8)
return ret
void map_fat_cluster (unsigned c, unsigned offset = 0):
read_block ((hidden_sectors + reserved_sectors + ((c * bits + 8 * offset) >> (sector_size_bits + 3))) << sector_size_bits)
unsigned make_bits (unsigned orig):
unsigned ret
for ret = 0; ret < 32; ++ret:
if orig == 1 << ret:
return ret
Iris::panic (ret, "non-power of 2")
return ret
void reset ():
read_block (0)
if data[0x1fe] != 0x55 || (data[0x1ff] & 0xff) != 0xaa:
kdebug ("invalid boot record signature in fat device\n")
for unsigned i = 0; i < 8; ++i:
oem[i] = data[3 + i]
sector_size_bits = make_bits (read_num (data + 0xb, 2))
sectors_per_cluster_bits = make_bits (read_num (data + 0xd, 1))
cluster_size_bits = sector_size_bits + sectors_per_cluster_bits
reserved_sectors = read_num (data + 0xe, 2)
num_fats = read_num (data + 0x10, 1)
root_entries = read_num (data + 0x11, 2)
sectors = read_num (data + 0x13, 2)
media = read_num (data + 0x15, 1)
sectors_per_fat = read_num (data + 0x16, 2)
sectors_per_track = read_num (data + 0x18, 2)
heads = read_num (data + 0x1a, 2)
hidden_sectors = read_num (data + 0x1c, 4)
if !sectors:
sectors = read_num (data + 0x20, 4)
if Iris::Num (sectors).value () << sector_size_bits > device_size.value ():
sectors = device_size.value () >> sector_size_bits
kdebug ("warning: limiting sectors because of limited device size\n")
root_sectors = (root_entries * 32 + (1 << sector_size_bits) - 1) >> sector_size_bits
header_sectors = hidden_sectors + reserved_sectors + sectors_per_fat * num_fats + root_sectors
clusters = (sectors - header_sectors) >> sectors_per_cluster_bits
unsigned skip
if clusters >= 65525:
bits = 32
sectors_per_fat = read_num (data + 0x24, 4)
active_fat = read_num (data + 0x28, 2)
write_all_fats = active_fat & 0x80
active_fat &= 0xf
fs_version = read_num (data + 0x2a, 2)
root_cluster = read_num (data + 0x2c, 4)
fsinfo_sector = read_num (data + 0x30, 2)
boot_backup_sector = read_num (data + 0x32, 2)
skip = 0x40 - 0x24
else:
if clusters < 4085:
bits = 12
else:
bits = 16
skip = 0
active_fat = 0
write_all_fats = true
fs_version = 0
root_cluster = 0
fsinfo_sector = 0
boot_backup_sector = 0
unsigned fat_entries_per_sector = (8 << sector_size_bits) / bits
unsigned fat_entries = sectors_per_fat * fat_entries_per_sector
if clusters + 2 > fat_entries:
clusters = fat_entries - 2
kdebug ("warning: limiting clusters because of limited sector count\n")
drive = read_num (data + skip + 0x24, 1)
current_head = read_num (data + skip + 0x25, 1)
if data[skip + 0x26] == 0x29:
volume_id = read_num (data + skip + 0x27, 4)
for unsigned i = 0; i < 0xb; ++i:
label[i] = data[skip + 0x2b + i]
char *id = data + skip + 0x36
if id[0] != 'F' || id[1] != 'A' || id[2] != 'T' || id[5] != ' ' || id[6] != ' ' || id[7] != ' ':
kdebug ("warning: file system type field was not 'FATxx '\n")
else:
switch bits:
case 12:
if id[3] != '1' || id[4] != '2':
kdebug ("warning: id for fat12 is not FAT12\n")
break
case 16:
if id[3] != '1' || id[4] != '6':
kdebug ("warning: id for fat16 is not FAT16\n")
break
case 32:
if id[3] != '3' || id[4] != '2':
kdebug ("warning: id for fat32 wat not FAT32")
break
else:
volume_id = 0
for unsigned i = 0; i < 0xb; ++i:
label[i] = 0
if fsinfo_sector:
read_block (fsinfo_sector << sector_size_bits)
if (data[0] & 0xff) != 0x52 || (data[1] & 0xff) != 0x52 || (data[2] & 0xff) != 0x6a || (data[3] & 0xff) != 0x41 || (data[0x1e4] & 0xff) != 0x72 || (data[0x1e5] & 0xff) != 0x72 || (data[0x1e6] & 0xff) != 0x4a || (data[0x1e7] & 0xff) != 0x61 || (data[0x1fe] & 0xff) != 0x55 || (data[0x1ff] & 0xff) != 0xaa:
kdebug ("invalid signature in fsinfo structure\n")
free_clusters = read_num (data + 0x1e8, 4)
last_alloced = read_num (data + 0x1ec, 4)
else:
free_clusters = ~0
last_alloced = ~0
// Now read the FAT.
bad_clusters = 0
fat = new unsigned[clusters]
unsigned counted_free_clusters = 0
for unsigned c = 0; c < clusters; ++c:
// reduced cluster.
unsigned rc = c & (1 << sector_size_bits) - 1
// The next line does nothing most of the time.
map_fat_cluster (c)
switch bits:
case 12:
fat[c] = data[(rc + 2) * 2] & 0xff
// There may be a sector boundary in the middle of the entry, so optionally reread.
map_fat_cluster (c, 1)
fat[c] |= (data[(rc + 2) * 2 + 1] & 0xff) << 8
if c & 1:
fat[c] >>= 4
else:
fat[c] &= 0xfff
break
case 16:
fat[c] = read_num (data + (rc + 2) * 2, 2)
break
case 32:
fat[c] = read_num (data + (rc + 2) * 4, 4)
break
// Correct for the crazy +2 offset, and keep a list of bad and free clusters.
if fat[c] == 0:
// Free cluster.
fat[c] = first_free_cluster
first_free_cluster = c
++counted_free_clusters
else if fat[c] == 1:
// Invalid value.
Iris::panic (0, "entry is '1' in fat.")
else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff:
// Last cluster in chain.
fat[c] = ~0
else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7:
// Bad cluster.
fat[c] = first_bad_cluster
first_bad_cluster = c
++bad_clusters
else:
// Non-last cluster in chain.
fat[c] -= 2
unsigned fat_lookup (unsigned first_cluster, unsigned cluster):
while cluster--:
first_cluster = fat[first_cluster]
if first_cluster == ~0:
kdebug ("sector beyond end of file requested\n")
return ~0
return first_cluster
struct File:
Fat *fat
unsigned size
unsigned first_cluster
char name[11]
bool archive, readonly, system, hidden, directory, volume
unsigned create_second, create_minute_hour, create_date, access_date, time, date
void load_cluster (unsigned idx, Iris::Page p = page, unsigned offset = 0):
unsigned cluster = fat->fat_lookup (first_cluster, idx >> fat->cluster_size_bits)
kdebug ("loading cluster ")
kdebug_num (idx)
kdebug ("@")
kdebug_num (cluster)
kdebug (" from file\n")
if cluster == ~0:
kdebug ("invalid cluster requested from file\n")
return
read_block ((fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) << fat->sector_size_bits, p, 1 << fat->cluster_size_bits, offset)
kdebug ("sector ")
kdebug_num (fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits))
kdebug ("\n")
void get_dir_entry (unsigned dir, unsigned idx, File *f):
f->fat = this
unsigned sector = idx >> (sector_size_bits - 5)
unsigned num = (idx << 5) & ~BLOCK_MASK
Iris::Num hwsector
if dir == ROOT_CLUSTER:
if sector < root_sectors:
hwsector = header_sectors - root_sectors + sector
else:
hwsector = ~0
else:
unsigned entry = fat_lookup (dir, sector)
if entry == ~0:
hwsector = ~0
else:
hwsector = header_sectors + (Iris::Num (entry).value () << sectors_per_cluster_bits)
if hwsector.value () == ~0:
kdebug ("invalid sector requested from directory\n")
f->first_cluster = ~0
return
read_block (hwsector.value () << sector_size_bits)
char *e = &data[num]
for unsigned i = 0; i < 11; ++i:
f->name[i] = e[i]
f->archive = e[0xb] & 0x20
f->readonly = e[0xb] & 0x10
f->system = e[0xb] & 0x8
f->hidden = e[0xb] & 0x4
f->directory = e[0xb] & 0x2
f->volume = e[0xb] & 0x1
f->create_second = read_num (e + 0xd, 1)
f->create_minute_hour = read_num (e + 0xe, 2)
f->create_date = read_num (e + 0x10, 2)
f->access_date = read_num (e + 0x12, 2)
f->time = read_num (e + 0x16, 1)
f->date = read_num (e + 0x18, 1)
f->size = read_num (e + 0x1c, 4)
f->first_cluster = (read_num (e + 0x14, 2) << 16 | read_num (e + 0x1a, 2)) - 2
// Capability encoding.
// 0:ROOT_CLUSTER = non fat-32 root directory.
// 0:cluster = other directory.
// cluster:index = file index from directory at cluster.
// cluster|0x80000000:index = filename for file with index from directory at cluster.
Iris::Num start ():
init_alloc ()
current_block = ~0
dev = Iris::my_parent.get_capability <Iris::WString> ()
if dev.get_align_bits () > SECTOR_BITS:
kdebug ("fat device doesn't support 512 byte access")
return 1
device_size = dev.get_size ()
data = (char *)0x15000; //alloc_space (1)
page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
Iris::my_memory.map (page, (unsigned)data)
Fat fat
fat.reset ()
fat.print_br ()
Iris::Cap root
if fat.root_cluster:
root = Iris::my_receiver.create_capability (Iris::Num (fat.root_cluster, 0))
else:
root = Iris::my_receiver.create_capability (Iris::Num (ROOT_CLUSTER, 0))
Iris::my_parent.provide_capability <Iris::Directory> (root.copy ())
Iris::free_cap (root)
while true:
Iris::wait ()
unsigned dir = Iris::recv.protected_data.h
if dir & 0x80000000:
// File name.
unsigned idx = Iris::recv.protected_data.l
Iris::Cap reply = Iris::get_reply ()
unsigned num = Iris::recv.data[1].l
unsigned size = Iris::recv.data[0].h >> 16
unsigned cmd = Iris::recv.data[0].l
Fat::File f
fat.get_dir_entry (dir & ~0x80000000, idx, &f)
switch cmd:
case Iris::String::GET_SIZE:
kdebug ("filename size requested\n")
reply.invoke (11)
break
case Iris::String::GET_CHARS:
//kdebug ("filename chars requested\n")
/**/union { unsigned u[4]; char c[16]; } u
for unsigned k = 0; k < 4; ++k:
u.u[k] = 0
for unsigned k = 0; k + num < 11; ++k:
u.c[k] = f.name[k + num]
reply.invoke (Iris::Num (u.u[0], u.u[1]), Iris::Num (u.u[2], u.u[3]))
break
case Iris::String::GET_ALIGN_BITS:
kdebug ("filename align requested\n")
reply.invoke (0)
break
case Iris::String::GET_BLOCK:
default:
Iris::panic (Iris::recv.data[0].l, "invalid request for fat filename")
Iris::free_cap (reply)
else if dir:
// File.
unsigned idx = Iris::recv.protected_data.l
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Num num = Iris::recv.data[1]
unsigned size = Iris::recv.data[0].h >> 16
unsigned offset = Iris::recv.data[0].h & 0xffff
unsigned cmd = Iris::recv.data[0].l
Fat::File f
fat.get_dir_entry (dir, idx, &f)
switch cmd:
case Iris::String::GET_SIZE:
kdebug ("file size requested\n")
reply.invoke (f.size)
break
case Iris::String::GET_CHARS:
kdebug ("file chars requested\n")
unsigned mask = 1 << (fat.cluster_size_bits) - 1
f.load_cluster (num.l & ~mask)
unsigned n = num.l & mask & ~0xf
unsigned *dat = (unsigned *)(data + n)
reply.invoke (Iris::Num (dat[0], dat[1]), Iris::Num (dat[2], dat[3]))
break
case Iris::String::GET_ALIGN_BITS:
kdebug ("file align requested\n")
reply.invoke (fat.cluster_size_bits)
break
case Iris::String::GET_BLOCK:
kdebug ("file block requested\n")
unsigned mask = 1 << (fat.cluster_size_bits) - 1
if offset > PAGE_SIZE:
kdebug ("invalid offset requested\n")
break
if size + offset > PAGE_SIZE:
size = PAGE_SIZE - offset
for unsigned i = 0; i < size; i += 1 << fat.cluster_size_bits:
f.load_cluster ((num.l & ~mask) + i, arg, i + offset)
reply.invoke ()
break
case Iris::WString::TRUNCATE:
case Iris::WString::SET_CHARS:
case Iris::WString::SET_BLOCK:
Iris::panic (Iris::recv.data[0].l, "writing to files not supported yet")
default:
Iris::panic (Iris::recv.data[0].l, "invalid request for fat file")
Iris::free_cap (reply)
Iris::free_cap (arg)
else:
// Directory.
if Iris::recv.protected_data.l != ROOT_CLUSTER:
// Normal directory.
switch Iris::recv.data[0].l:
case Iris::Directory::GET_SIZE:
kdebug ("dir size requested\n")
Iris::recv.reply.invoke ()
break
case Iris::Directory::GET_NAME:
kdebug ("dir name requested\n")
Iris::recv.reply.invoke ()
break
case Iris::Directory::GET_FILE_RO:
kdebug ("dir file requested\n")
Iris::Cap reply = Iris::get_reply ()
Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l))
reply.invoke (0, 0, ret.copy ())
Iris::free_cap (reply)
Iris::free_cap (ret)
break
case Iris::Directory::GET_FILE_INFO:
kdebug ("dir file info requested\n")
Iris::recv.reply.invoke ()
break
case Iris::Directory::LOCK_RO:
case Iris::Directory::UNLOCK_RO:
kdebug ("dir lock or unlock requested\n")
Iris::recv.reply.invoke ()
break
default:
kdebug ("invalid dir operation requested\n")
Iris::recv.reply.invoke ()
break
else:
// Non-fat32 root directory.
switch Iris::recv.data[0].l:
case Iris::Directory::GET_SIZE:
kdebug ("root size requested\n")
Iris::recv.reply.invoke (fat.root_entries)
break
case Iris::Directory::GET_NAME:
//kdebug ("root name requested\n")
Iris::Cap reply = Iris::get_reply ()
Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l | 0x80000000))
reply.invoke (0, 0, ret.copy ())
Iris::free_cap (reply)
Iris::free_cap (ret)
break
case Iris::Directory::GET_FILE_RO:
kdebug ("root file requested\n")
Iris::Cap reply = Iris::get_reply ()
Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l))
reply.invoke (0, 0, ret.copy ())
Iris::free_cap (reply)
Iris::free_cap (ret)
break
case Iris::Directory::GET_FILE_INFO:
kdebug ("root file info requested\n")
Iris::recv.reply.invoke ()
break
case Iris::Directory::LOCK_RO:
case Iris::Directory::UNLOCK_RO:
kdebug ("root lock or unlock requested\n")
Iris::recv.reply.invoke ()
break
default:
kdebug ("invalid root operation requested\n")
Iris::recv.reply.invoke ()
break

View File

@ -182,7 +182,7 @@ static Iris::Caps load (char const *name, unsigned name_len, unsigned &size, Iri
unsigned slot = target.use ()
for unsigned p = 0; p < pages; ++p:
Iris::set_recv_arg (Iris::Cap (slot, p))
file.get_page (p << PAGE_BITS)
file.get_block (p << PAGE_BITS)
Iris::free_slot (slot)
Iris::free_cap (file)
root.unlock_ro ()
@ -426,9 +426,9 @@ static void parse_line (char *&line, unsigned maxlen):
Iris::panic (0, "capability given out twice")
(*d)->dev->client = &**p
++(*p)->num_waiting
kdebug ("registered give device: ")
kdebug_num ((*d)->type)
kdebug ("\n")
//kdebug ("registered give device: ")
//kdebug_num ((*d)->type)
//kdebug ("\n")
else if match (start, maxlen, "include"):
unsigned name_len
char *name = get_filename (line, maxlen, name_len)
@ -492,11 +492,11 @@ Iris::Num start ():
if !d:
Iris::panic (type, "unregistered device requested")
Iris::recv.reply.invoke (0, 0, (*d)->dev->cap)
kdebug ("given device ")
kdebug_num (type)
kdebug (":")
kdebug_num (index)
kdebug ("\n")
//kdebug ("given device ")
//kdebug_num (type)
//kdebug (":")
//kdebug_num (index)
//kdebug ("\n")
break
case Iris::Parent::PROVIDE_CAPABILITY:
if Iris::recv.data[1].h != 0:
@ -515,14 +515,14 @@ Iris::Num start ():
if (*d)->client:
if !--(*d)->client->num_waiting:
(*d)->client->run ()
kdebug ("provided ")
kdebug_num ((*d)->type)
kdebug (":")
kdebug_num ((*d)->index)
kdebug ("\n")
//kdebug ("provided ")
//kdebug_num ((*d)->type)
//kdebug (":")
//kdebug_num ((*d)->index)
//kdebug ("\n")
break
case Iris::Parent::INIT_DONE:
kdebug ("init done\n")
//kdebug ("init done\n")
Iris::recv.reply.invoke ()
if caller == sysreq->server:
Iris::Cap cap = Iris::my_receiver.create_capability (SYSREQ)
@ -530,6 +530,15 @@ Iris::Num start ():
Iris::free_cap (cap)
kdebug ("registered sysreq\n")
break
case Iris::Parent::EXIT:
kdebug ("child exits with code ")
// TODO: print name.
kdebug_num (Iris::recv.data[1].h)
kdebug (":")
kdebug_num (Iris::recv.data[1].l)
kdebug ("\n")
// TODO: destroy memory.
break
default:
// TODO.
kdebug ("child request: ")

129
source/partition.ccp Normal file
View File

@ -0,0 +1,129 @@
#pypp 0
#include <iris.hh>
#include <devices.hh>
#define NUM_PARTITIONS 4
#define SECTOR_BITS 9
#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
struct Partition:
static Iris::Num device_size
unsigned lba_start, lba_size
unsigned type
bool active
Iris::Num start, size
static unsigned read_num (char *data):
return data[0] & 0xff | (data[1] & 0xff) << 8 | (data[2] & 0xff) << 16 | (data[3] & 0xff) << 24
void read (char *data):
if data[0] == 0:
active = false
else:
active = true
if (data[0] & 0xff) != 0x80:
kdebug ("Warning: invalid active code ")
kdebug_num (data[0], 2)
kdebug ("\n")
type = data[4] & 0xff
lba_start = read_num (data + 8)
lba_size = read_num (data + 12)
start = Iris::Num (lba_start).value () << SECTOR_BITS
size = Iris::Num (lba_size).value () << SECTOR_BITS
//kdebug ("Partition read: ")
//kdebug_num (lba_start)
//kdebug ("+")
//kdebug_num (lba_size)
//kdebug ("\n")
Iris::Num Partition::device_size
static Iris::WString dev
static void read_block (Iris::Num idx, Iris::Page page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
idx = idx.value () >> SECTOR_BITS
offset &= ~PAGE_MASK
if size + offset > PAGE_SIZE:
size = PAGE_SIZE - offset
size >>= SECTOR_BITS
for unsigned i = 0; i < size; ++i:
dev.get_block ((idx.value () + i) << SECTOR_BITS, 1 << SECTOR_BITS, (i << SECTOR_BITS) + offset, page)
Iris::Num start ():
Partition::device_size = 0
dev = Iris::my_parent.get_capability <Iris::WString> ()
if dev.get_align_bits () > SECTOR_BITS:
kdebug ("partitioned device doesn't support 512 byte access")
return 1
Partition::device_size = dev.get_size ()
Iris::Page page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
char *buffer = (char *)0x15000
unsigned *ubuffer = (unsigned *)buffer
Iris::my_memory.map (page, (unsigned)buffer)
read_block (0, page)
if buffer[0x1fe] != 0x55 || (buffer[0x1ff] & 0xff) != 0xaa:
kdebug ("invalid mbr signature\n")
Partition partition[NUM_PARTITIONS]
Iris::Cap cap
for unsigned i = 0; i < NUM_PARTITIONS; ++i:
partition[i].read (buffer + 0x1be + 0x10 * i)
cap = Iris::my_receiver.create_capability (i)
Iris::my_parent.provide_capability <Iris::WString> (cap.copy (), i)
Iris::free_cap (cap)
page.set_flags (0, Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
switch Iris::recv.data[0].l:
case Iris::String::GET_SIZE:
Iris::recv.reply.invoke (partition[Iris::recv.protected_data.l].size)
break
case Iris::String::GET_CHARS:
Iris::Cap reply = Iris::get_reply ()
Iris::Num request = Iris::recv.data[1]
Iris::Num offset = (partition[Iris::recv.protected_data.l].start.value () + (request.value () & BLOCK_MASK)) & 0xf
unsigned page_offset = request.l & ~BLOCK_MASK
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
read_block (offset, page)
reply.invoke (Iris::Num (ubuffer[page_offset >> 2 + 0], ubuffer[page_offset >> 2 + 1]), Iris::Num (ubuffer[page_offset >> 2 + 2], ubuffer[page_offset >> 2 + 3]))
page.set_flags (0, Iris::Page::PAYING | Iris::Page::FRAME)
Iris::free_cap (reply)
break
case Iris::String::GET_ALIGN_BITS:
Iris::recv.reply.invoke (SECTOR_BITS)
break
case Iris::String::GET_BLOCK:
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Num p = Iris::recv.data[1].value () & BLOCK_MASK
Iris::Num offset = partition[Iris::recv.protected_data.l].start.value ()
unsigned size = Iris::recv.data[0].h >> 16
unsigned out_offset = Iris::recv.data[0].h & 0xffff
//kdebug ("partition sending sector ")
//kdebug_num (offset.h)
//kdebug (":")
//kdebug_num (offset.l)
//kdebug (" + ")
//kdebug_num (p.h)
//kdebug (":")
//kdebug_num (p.l)
//kdebug (" = ")
//kdebug_num (Iris::Num (offset.value () + p.value ()).h)
//kdebug (":")
//kdebug_num (Iris::Num (offset.value () + p.value ()).l)
//kdebug ("\n")
read_block (offset.value () + p.value (), arg, size, out_offset)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (arg)
break
case Iris::WString::SET_CHARS:
case Iris::WString::SET_BLOCK:
Iris::panic (Iris::recv.data[0].l, "writing to partitions not supported yet")
case Iris::WString::TRUNCATE:
default:
Iris::panic (Iris::recv.data[0].l, "invalid request for partition handler")

View File

@ -21,9 +21,37 @@
#include "arch.hh"
class Mmc:
static unsigned const PORT = 3
static unsigned const PIN = 2
bool check_sdio ()
public:
enum Response_type:
NONE = MSC_CMDAT_RESPONSE_NONE
DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN
R1 = MSC_CMDAT_RESPONSE_R1
R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY
R2 = MSC_CMDAT_RESPONSE_R2
R3 = MSC_CMDAT_RESPONSE_R3
R4 = MSC_CMDAT_RESPONSE_R4
R5 = MSC_CMDAT_RESPONSE_R5
R6 = MSC_CMDAT_RESPONSE_R6
R7 = MSC_CMDAT_RESPONSE_R7
static unsigned const POWER_PORT = 3
static unsigned const POWER_PIN = 2
struct CID:
unsigned mid
char oid[2]
char pnm[5]
unsigned prv
unsigned psn
unsigned year
unsigned month
struct CSD:
unsigned c_size
unsigned c_size_mult
unsigned read_bl_len, write_bl_len
bool copy
bool perm_write_protect
bool tmp_write_protect
bool send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response = NULL)
void check_sd ()
void check_sdmem ()
void check_mmc ()
public:
@ -31,23 +59,158 @@ class Mmc:
void detect ()
void release ()
void interrupt ()
CID const &get_cid ():
return cid
unsigned get_num_blocks ():
return num_blocks
unsigned get_read_block_size ():
return read_block_size
unsigned get_block_bits ():
return csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len
void fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
private:
unsigned rca
bool have_sdmem, have_io
CID cid
CSD csd
unsigned num_blocks, read_block_size
Iris::Page buffer_page
static unsigned const buffer = 0x15000
bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response):
MSC_CMD = cmd
MSC_ARG = arg
MSC_CMDAT = response_type
Iris::register_interrupt (IRQ_MSC)
msc_start_op ()
Iris::wait_for_interrupt (IRQ_MSC)
//kdebug ("cmd: ")
//kdebug_num (cmd)
unsigned stat = MSC_STAT
//kdebug (", stat: ")
//kdebug_num (stat)
//kdebug ("\n")
if stat & MSC_STAT_CRC_RES_ERR:
Iris::panic (0, "crc error in mmc response")
return false
if stat & MSC_STAT_TIME_OUT_RES:
//kdebug ("time out waiting for mmc response\n")
return false
if response_type == R2:
unsigned d = MSC_RES
if d >> 8 != 0x3f:
Iris::panic (d, "invalid r2 response")
if cmd == 3:
// Read out result.
cid.mid = d & 0xff
d = MSC_RES
cid.oid[0] = d >> 8
cid.oid[1] = d & 0xff
d = MSC_RES
cid.pnm[0] = d >> 8
cid.pnm[1] = d & 0xff
d = MSC_RES
cid.pnm[2] = d >> 8
cid.pnm[3] = d & 0xff
d = MSC_RES
cid.pnm[4] = d >> 8
cid.prv = d & 0xff
d = MSC_RES
cid.psn = d << 16
d = MSC_RES
cid.psn |= d
d = MSC_RES
cid.year = 2000 + (d >> 4 & 0xff)
cid.month = d & 0xf
else:
// Header (8) 1.0 1.0
// Read out csd.
// Ignore csd_structure. 2 (+ 6) 1.0 2.0 ***
d = MSC_RES
// Ignore taac and nsac. 8 + 8 2.0 4.0 ***
d = MSC_RES
// Ignore tran_speed, ccc. 8 + 8/12 2.0 6.0 ***
d = MSC_RES
// Ignore rest of ccc. 4/12 0.4 6.4
// 4 0.4 7.0
csd.read_bl_len = (d >> 8) & 0xf
// Ignore read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp. 1 + 1 + 1 + 1 (+ 2) 0.6 7.6
// 2/12 0.2 8.0 ***
csd.c_size = (d & 0x0003) << 10
d = MSC_RES
// 10/12 1.2 9.2
csd.c_size |= d >> 6
// Ignore vdd_r_cur_min, vdd_r_cur_max. 3 + 3 0.6 10.0 ***
d = MSC_RES
// Ignore vdd_w_cur_min, vdd_w_cur_max. 3 + 3 0.6 10.6
// 3 0.3 11.1
csd.c_size_mult = (d >> 7) & 0x7
// Ignore erase_blk_enable, sector_size. 1 + 6/7 0.7 12.0 ***
d = MSC_RES
// Ignore rest of sector_size, wp_grp_size, wp_grp_enable, r2w_factor. 1/7 + 7 + 1 (+ 2) + 3 1.6 13.6
// 2/4 0.4 14.0 ***
csd.write_bl_len = (d << 2) & 0xc
d = MSC_RES
// 2/4 0.2 14.2
csd.write_bl_len |= (d >> 14) & 0x3
// Ignore write_bl_partial, file_format_grp. 1 (+ 5) + 1 0.7 15.1
// 1 0.1 15.2
csd.copy = d & 0x40
// 1 0.1 15.3
csd.perm_write_protect = d & 0x20
// 1 0.1 15.4
csd.tmp_write_protect = d & 0x10
// Ignore file_format. 2 (+ 2) 0.4 16.0 ***
read_block_size = 1 << csd.read_bl_len
num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2)
else if response_type != NONE:
unsigned r = MSC_RES
if response_type == R3:
if r >> 8 != 0x3f:
Iris::panic (r, "r3 response was not 3f")
else if r >> 8 != cmd:
Iris::panic (r, "response doesn't match command")
r <<= 24
r |= MSC_RES << 8
r |= MSC_RES & 0xff
if response:
*response = r
//kdebug ("extra response fifo read: ")
//for unsigned i = 0; i < 9; ++i:
//kdebug (" ")
//kdebug_num (MSC_RES, 4)
//kdebug ("\n")
MSC_IREG = MSC_IREG_END_CMD_RES
return true
void Mmc::reset ():
// Create a buffer to use for data transfer.
buffer_page = Iris::my_memory.create_page ()
Iris::my_memory.map (buffer_page, buffer)
// Reset all state, by faking a release event.
release ()
// Enable slow clock to msc.
CPM_MSCCDR = ~0
cpm_start_msc ()
// Enable msc pins.
gpio_as_msc ()
// Disable power to card.
gpio_as_gpio (PORT, 1 << PIN)
gpio_as_output (PORT, 1 << PIN)
gpio_disable_pull (PORT, 1 << PIN)
gpio_set (PORT, 1 << PIN)
gpio_as_gpio (POWER_PORT, 1 << POWER_PIN)
gpio_as_output (POWER_PORT, 1 << POWER_PIN)
gpio_disable_pull (POWER_PORT, 1 << POWER_PIN)
gpio_set (POWER_PORT, 1 << POWER_PIN)
// Stop the clock.
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
while MSC_STAT & MSC_STAT_CLK_EN:
Iris::schedule ()
//kdebug (",")
Iris::sleep (1)
// Reset controller and inserted devices.
MSC_STRPCL = MSC_STRPCL_RESET
while MSC_STAT & MSC_STAT_IS_RESETTING:
//kdebug (":")
Iris::sleep (1)
// Initialize registers.
MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_128
@ -55,82 +218,166 @@ void Mmc::reset ():
MSC_RDTO = ~0
MSC_BLKLEN = 0x200
MSC_NOB = 0
MSC_IMASK = ~0
MSC_IREG = ~0
MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ | MSC_IMASK_TXFIFO_WR_REQ)
MSC_ARG = 0
// Reset controller and inserted devices.
MSC_STRPCL = MSC_STRPCL_RESET
while MSC_STAT & MSC_STAT_IS_RESETTING:
Iris::schedule ()
// Start the clock.
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
// Set cards, if any, to idle.
MSC_CMD = 0
MSC_CMDAT = MSC_CMDAT_RESPONSE_NONE
Iris::register_interrupt (IRQ_MSC)
msc_start_op ()
while !msc_ireg_end_cmd_res ():
Iris::schedule ()
Iris::wait_for_interrupt (IRQ_MSC)
msc_ireg_clear_end_cmd_res ()
// Reset SDIO device, if any.
MSC_CMD = 52
MSC_ARG = 0x88000C08
MSC_CMDAT = MSC_CMDAT_RESPONSE_R5
Iris::register_interrupt (IRQ_MSC)
msc_start_op ()
while !msc_ireg_end_cmd_res ():
Iris::schedule ()
Iris::wait_for_interrupt (IRQ_MSC)
msc_ireg_clear_end_cmd_res ()
bool Mmc::check_sdio ():
// 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
// 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
// 4. If C-bit in the response is ready (the initialization has finished), go to 6.
// 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
// 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else
// it is only a SDIO card.
// 7. If it is a combo card, go to check SDMEM to initialize the memory part.
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned
// from the response.
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
// 10. Go to check MMC, because we can assure that there is no SDMEM card.
return false
void Mmc::check_sdmem ():
// 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
// 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
// 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
// 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
// 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
// 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
// 10. Go to check MMC.
void Mmc::check_mmc ():
//kdebug ("checking mmc\n")
// 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
// 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
// 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
// 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
// 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
// 6. If the response timeout occurs, goto 9.
// 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
// 8. If there are other MMC cards, then go to 5.
// 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
// 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
// 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
// 6. If the response timeout occurs, goto 9.
// 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
void Mmc::check_sdmem ():
kdebug ("checking sdmem\n")
send (0, 0, NONE)
// 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
// 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
unsigned code
bool hc = false
if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa:
kdebug ("hc\n")
hc = true
if !send (55, 0, R1, &code):
check_mmc ()
return
// 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
check_mmc ()
return
// 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
// 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
unsigned retries = 100
while !(code & (1 << 31)) && --retries:
if !send (55, 0, R1, &code):
return
if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
return
Iris::sleep (1)
if !(code & (1 << 31)):
Iris::panic (code, "card fails to finish setting up")
// 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
if !send (2, 0, R2):
Iris::panic (0, "card failed to send CID")
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
rca = 0
while !rca:
if !send (3, 0, R6, &rca):
Iris::panic (0, "card failed to provide rca")
rca &= 0xffff0000
kdebug ("received rca ")
kdebug_num (rca >> 16, 4)
kdebug ("\n")
have_sdmem = true
void Mmc::check_sd ():
//kdebug ("checking sdio\n")
if !send (0, 0, NONE):
Iris::panic (0, "unable to reset cards?")
// 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
// 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
unsigned code
if !send (5, 1 << 20, R4, &code) || !(code & (7 << 28)):
check_sdmem ()
return
// 4. If C-bit in the response is ready (the initialization has finished), go to 6.
// 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
while !(code & (1 << 31)):
if !send (5, 1 << 20, R4, &code):
Iris::panic (0, "invalid response to cmd 5")
// 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else it is only a SDIO card.
// 7. If it is a combo card, go to check SDMEM to initialize the memory part.
have_io = true
if code & (1 << 27):
check_sdmem ()
return
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned from the response.
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
rca = 0
while rca == 0:
if !send (3, 0, R6, &rca):
Iris::panic (0, "unable to set rca")
rca &= 0xffff0000
check_mmc ()
void Mmc::detect ():
kdebug ("mmc detect\n")
gpio_clear (PORT, 1 << PIN)
if check_sdio ():
check_sdmem ()
gpio_clear (POWER_PORT, 1 << POWER_PIN)
check_sd ()
check_mmc ()
if have_sdmem:
if !send (9, rca, R2):
Iris::panic (0, "unable to request csd")
if !send (7, rca, R1B):
Iris::panic (0, "unable to select sdmem")
kdebug ("found device; size = ")
kdebug_num (num_blocks)
kdebug (" * ")
kdebug_num (read_block_size)
kdebug (" = ")
kdebug_num (num_blocks * read_block_size)
kdebug ("\n")
void Mmc::release ():
kdebug ("mmc release\n")
gpio_set (PORT, 1 << PIN)
gpio_set (POWER_PORT, 1 << POWER_PIN)
have_sdmem = false
have_io = false
read_block_size = 0
num_blocks = 0
void Mmc::interrupt ():
kdebug ("mmc interrupt\n")
void Mmc::fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
if address.h:
Iris::panic (0, "page too high: not supported")
return
unsigned blockmask = ~((1 << get_block_bits ()) - 1)
unsigned p = address.l & blockmask
size &= blockmask
offset &= ~PAGE_MASK
if size + offset > PAGE_SIZE:
size = PAGE_SIZE - offset
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
page.share (buffer_page)
buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
MSC_NOB = 1
MSC_BLKLEN = read_block_size
for unsigned a = 0; a < size; a += 1 << get_block_bits ():
if !send (17, p + a, DATA):
Iris::panic (0, "unable to request data")
for unsigned aa = 0; aa < read_block_size; aa += 4:
Iris::register_interrupt (IRQ_MSC)
Iris::wait_for_interrupt (IRQ_MSC)
*(unsigned *)(buffer + a + aa + offset) = MSC_RXFIFO
MSC_IREG = MSC_IREG_DATA_TRAN_DONE
static Mmc mmc
enum types:
DETECT
@ -141,7 +388,6 @@ Iris::Num start ():
map_gpio ()
map_cpm ()
Mmc mmc
mmc.reset ()
Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
@ -178,7 +424,34 @@ Iris::Num start ():
mmc.interrupt ()
break
case REQUEST:
kdebug ("sd+mmc request\n")
//kdebug ("sd+mmc request ")
//kdebug_num (Iris::recv.data[0].l)
//kdebug ("\n")
switch Iris::recv.data[0].l:
case Iris::String::GET_SIZE:
unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size ()
Iris::recv.reply.invoke (size)
break
case Iris::String::GET_CHARS:
Iris::panic (0, "get chars from mmc not supported yet")
break
case Iris::String::GET_ALIGN_BITS:
Iris::recv.reply.invoke (mmc.get_block_bits ())
break
case Iris::String::GET_BLOCK:
Iris::Cap reply = Iris::get_reply ()
Iris::Page page = Iris::get_arg ()
mmc.fill_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
reply.invoke ()
Iris::free_cap (page)
Iris::free_cap (reply)
break
case Iris::WString::SET_CHARS:
case Iris::WString::SET_BLOCK:
// Fall through: don't support writing yet.
case Iris::WString::TRUNCATE:
default:
Iris::panic (0, "unexpected event for sd+mmc")
break
default:
Iris::panic (0, "unexpected request source for sd+mmc")

60
source/test.ccp Normal file
View File

@ -0,0 +1,60 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/test.ccp: Testing program.
// 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 <iris.hh>
#include <devices.hh>
bool match (char const *a, char const *b):
for unsigned i = 0; i < 11; ++i:
if a[i] != b[i]:
return false
return true
Iris::Num start ():
Iris::Directory dir = Iris::my_parent.get_capability <Iris::Directory> ()
dir.lock_ro ()
Iris::Num files = dir.get_size ()
for Iris::Num i = 0; i.value () < files.value (); i = i.value () + 1:
Iris::String f = dir.get_name (i)
char start[16]
f.get_chars (0, start)
if match (start, "TEST TXT"):
Iris::free_cap (f)
f = dir.get_file_ro (i)
dir.unlock_ro ()
Iris::Page p = f.get_block (0)
char *mapping = (char *)0x15000
Iris::my_memory.map (p, (unsigned)mapping)
for unsigned j = 0; j < PAGE_SIZE; ++j:
kdebug_char (mapping[j])
kdebug_char ('\n')
return 0
unsigned i
for i = 0; i < 16; ++i:
if start[i] != 0:
break
if i < 16:
for i = 0; i < 16; ++i:
kdebug_num (start[i], 2)
kdebug (" ")
for i = 0; i < 16; ++i:
kdebug_char (start[i])
kdebug ("\n")
Iris::free_cap (f)
kdebug ("file test.txt not found\n")
return 1

View File

@ -600,7 +600,7 @@ Iris::Num start ():
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
case Iris::String::GET_PAGE:
case Iris::String::GET_BLOCK:
default:
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
@ -669,9 +669,12 @@ Iris::Num start ():
case FILE:
//kdebug ("file request\n")
switch Iris::recv.data[0].l:
case Iris::String::GET_BLOCK:
if Iris::recv.data[0].h != PAGE_SIZE << 16:
Iris::panic (0, "unsupported get_block arguments for boot usb device driver")
// Fall through.
case Iris::String::GET_SIZE:
case Iris::String::GET_CHARS:
case Iris::String::GET_PAGE:
udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.h, reply, arg)
continue
default: