1 /* 2 * A dataspace server exposing regions of a MMC/SD card. 3 * 4 * Copyright (C) 2020, 2021, 2023, 2024 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (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, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/cpm-x1600.h> 23 #include <l4/devices/dma.h> 24 #include <l4/devices/dma-x1600.h> 25 #include <l4/devices/memory.h> 26 #include <l4/devices/msc-x1600.h> 27 28 #include <l4/re/c/util/cap_alloc.h> 29 #include <l4/sys/debugger.h> 30 #include <l4/sys/err.h> 31 #include <l4/sys/factory.h> 32 #include <l4/sys/icu.h> 33 #include <l4/sys/ipc.h> 34 #include <l4/sys/irq.h> 35 36 #include <ipc/thread.h> 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 41 #include <mem/memory_incremental.h> 42 #include <fsserver/page_queue_shared.h> 43 #include <fsserver/pages.h> 44 #include <resource/resource_server.h> 45 #include <systypes/env.h> 46 47 #include "msc_region_opener.h" 48 #include "msc_region_operations.h" 49 50 51 52 /* Common configuration. */ 53 54 static l4_cap_idx_t icucap; 55 56 57 58 /* Device and resource discovery. */ 59 60 static long item_in_range(long start, long end, long index) 61 { 62 if (start < end) 63 return start + index; 64 else if (start > end) 65 return start - index; 66 else 67 return start; 68 } 69 70 71 72 /* Common functions. */ 73 74 static int init_irq(int num, l4_cap_idx_t irq, l4_uint32_t start, l4_uint32_t end) 75 { 76 /* Create interrupt object. */ 77 78 long err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irq)); 79 80 if (err) 81 { 82 printf("Could not create IRQ object: %ld\n", err); 83 return 1; 84 } 85 86 /* Bind interrupt objects to IRQ numbers. */ 87 88 err = l4_error(l4_icu_bind(icucap, 89 item_in_range(start, end, num), 90 irq)); 91 92 if (err) 93 { 94 printf("Could not bind IRQ to the ICU: %ld\n", err); 95 return 1; 96 } 97 98 return 0; 99 } 100 101 102 103 /* Peripheral resources. */ 104 105 static Cpm_x1600_chip *cpm; 106 static Dma_x1600_chip *dma; 107 static Msc_x1600_chip *msc; 108 109 /* Obtain an abstraction for the memory card. */ 110 111 static MscRegionOperations *get_msc_region_operations(int msc_channel_num, 112 int dma_channel_num, 113 int card) 114 { 115 l4_addr_t cpm_base = 0, cpm_base_end = 0; 116 l4_addr_t dma_base = 0, dma_base_end = 0; 117 l4_addr_t msc_base = 0, msc_base_end = 0; 118 l4_addr_t msc_phys_base = 0, msc_phys_base_end = 0; 119 l4_uint32_t dma_irq_start = 0, dma_irq_end = 0; 120 l4_uint32_t msc_irq_start = 0, msc_irq_end = 0; 121 122 icucap = l4re_env_get_cap("icu"); 123 124 /* Obtain resource details describing I/O memory. */ 125 126 if (get_memory("x1600-cpm", &cpm_base, &cpm_base_end) < 0) 127 return NULL; 128 129 cpm = new Cpm_x1600_chip(cpm_base); 130 131 if (get_memory("x1600-dma", &dma_base, &dma_base_end) < 0) 132 return NULL; 133 134 dma = new Dma_x1600_chip(dma_base, dma_base_end, cpm); 135 136 if (get_irq("x1600-dma", &dma_irq_start, &dma_irq_end) < 0) 137 return NULL; 138 139 l4_cap_idx_t dma_irq = l4re_util_cap_alloc(); 140 141 if (init_irq(0, dma_irq, dma_irq_start, dma_irq_end)) 142 return NULL; 143 144 dma->enable(); 145 146 if (get_memory_complete("x1600-msc", &msc_base, &msc_base_end, 147 &msc_phys_base, &msc_phys_base_end) < 0) 148 return NULL; 149 150 msc = new Msc_x1600_chip(msc_phys_base, msc_base, msc_base_end, cpm); 151 152 if (get_irq("x1600-msc", &msc_irq_start, &msc_irq_end) < 0) 153 return NULL; 154 155 l4_cap_idx_t msc_irq = l4re_util_cap_alloc(); 156 157 if (init_irq(msc_channel_num, msc_irq, msc_irq_start, msc_irq_end)) 158 return NULL; 159 160 Dma_x1600_channel *dma_channel = dma->get_channel(dma_channel_num, dma_irq); 161 Msc_channel *msc_channel = msc->get_channel(msc_channel_num, msc_irq, dma_channel); 162 163 msc_channel->enable(); 164 165 if (card >= msc_channel->num_cards()) 166 return NULL; 167 168 struct dma_region region; 169 170 if (get_dma_region(512, 12, ®ion)) 171 return NULL; 172 173 return new MscRegionOperations(msc_channel, card, region); 174 } 175 176 177 178 /* Default number of pages for files. */ 179 180 const unsigned int MEMORY_PAGES = 20; 181 182 183 184 /* Server program. */ 185 186 int main(int argc, char *argv[]) 187 { 188 l4_debugger_set_object_name(l4re_env()->main_thread, "block_server"); 189 long err; 190 191 /* Introduce concurrency control. */ 192 193 err = ipc_thread_init(); 194 195 if (err) 196 { 197 printf("Initialisation error: %s\n", l4sys_errtostr(err)); 198 return 1; 199 } 200 201 if (argc < 4) 202 { 203 printf("Need a MSC channel/peripheral number, a DMA channel number, " \ 204 "and a card number.\n\n" \ 205 "A number of memory pages can be indicated for the use of the " \ 206 "server.\n\n" \ 207 "A named capability from the environment can be specified.\n"); 208 return 1; 209 } 210 211 int msc_channel_num = atoi(argv[1]); 212 int dma_channel_num = atoi(argv[2]); 213 int card = atoi(argv[3]); 214 215 unsigned int memory_pages = MEMORY_PAGES; 216 217 if (argc > 4) 218 memory_pages = atoi(argv[4]); 219 220 const char *server_name = (argc > 5) ? argv[5] : ENV_FILESYSTEM_SERVER_NAME; 221 222 /* Obtain a DMA space for associating allocated memory with physical 223 addresses. */ 224 225 l4_cap_idx_t dma_space; 226 227 err = get_dma_space(&dma_space); 228 229 if (err) 230 { 231 printf("Could not obtain DMA space: %s\n", l4sys_errtostr(err)); 232 return 1; 233 } 234 235 MscRegionOperations *ops = get_msc_region_operations(msc_channel_num, 236 dma_channel_num, 237 card); 238 239 if (ops == NULL) 240 { 241 printf("Could not access memory card peripheral.\n"); 242 return 1; 243 } 244 245 /* Some memory plus infrastructure. */ 246 247 MemoryIncremental mem(memory_pages, PAGE_SIZE, dma_space); 248 PageQueueShared queue; 249 Pages pages(&mem, &queue); 250 ResourceRegistry registry(&pages); 251 MscRegionOpener opener(®istry, ops); 252 253 /* Register a server associating it with the given object. */ 254 255 ResourceServer server(&opener); 256 server.bind(server_name); 257 258 printf("Starting server using %d pages...\n", memory_pages); 259 server.start(); 260 261 return 0; 262 } 263 264 // vim: tabstop=2 expandtab shiftwidth=2