Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / ll / ll.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: ll.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21/*
22 * Copyright (C) 2001, Sun Microsystems, Inc.
23 * All rights reserved.
24 */
25#pragma ident "@(#)1.10 04/08/04 SMI ll.cc"
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <assert.h>
30#include <errno.h>
31#include <dirent.h>
32#include <fcntl.h>
33#include <limits.h>
34#include <stdlib.h>
35#include <strings.h>
36#include <utime.h>
37#include <unistd.h>
38
39#include "types.h"
40#include "macrolib.h"
41#include "dr.h"
42#include "ll_impl.h"
43#include "ll_mod.h"
44#include "ui.h"
45
46static bool ll_trace = false;
47
48typedef void* TM_OPAQUE_DATA;
49
50ll_structT *LL::allocation_obj()
51{
52 sp = (ll_structT *) calloc(1, sizeof(ll_structT));
53 assert(sp);
54 return (sp);
55}
56
57int LL::reg_access(char *buf, LWord paddr, bool_t wr)
58{
59 uint32_t *reg = (uint32_t *)(buf + sizeof(uint64_t)-sizeof(uint32_t));
60
61 if (!wr) {
62 switch (paddr & LL_REG_ADDR_MASK) {
63 case LL_REG_SR:
64 *reg = LL::rd_status();
65 break;
66 case LL_REG_CR:
67 /* ignored */
68 break;
69 case LL_REG_ECR:
70 *reg = LL::rd_errorcode();
71 break;
72 case LL_REG_ARG_ADDR:
73 *reg = LL::rd_arg_addr();
74 break;
75 case LL_REG_RES_ADDR:
76 *reg = LL::rd_res_addr();
77 break;
78 default:
79 ui->error(
80 "%s: reg_access: read: invalid paddr 0x%llx\n", getName(),
81 paddr);
82 return (1);
83 }
84 } else {
85 switch (paddr & LL_REG_ADDR_MASK) {
86 case LL_REG_SR:
87 /* ignored */
88 break;
89 case LL_REG_CR:
90 LL::wr_control(*reg);
91 break;
92 case LL_REG_ECR:
93 /* ignored */
94 break;
95 case LL_REG_ARG_ADDR:
96 LL::wr_arg_addr(*reg);
97 break;
98 case LL_REG_RES_ADDR:
99 LL::wr_res_addr(*reg);
100 break;
101 default:
102 ui->error(
103 "%s: reg_access: write: invalid paddr 0x%llx\n", getName(),
104 paddr);
105 return (1);
106 }
107 }
108
109 return (0);
110}
111
112uint32_t LL::rd_status()
113{
114 return (sp->reg_sr);
115}
116
117uint32_t LL::rd_errorcode()
118{
119 return (sp->reg_ecr);
120}
121
122uint32_t LL::rd_arg_addr()
123{
124 return (sp->reg_arg_addr);
125}
126
127uint32_t LL::rd_res_addr()
128{
129 return (sp->reg_res_addr);
130}
131
132void LL::wr_control(uint32_t val)
133{
134 sp->reg_cr = val;
135 /* clear errorcode */
136 sp->reg_ecr = 0;
137
138 switch (sp->reg_cr) {
139 case LL_CR_READ:
140 LL::cmd_read();
141 break;
142 case LL_CR_WRITE:
143 LL::cmd_write();
144 break;
145 case LL_CR_GETATTR:
146 LL::cmd_getattr();
147 break;
148 case LL_CR_SETATTR:
149 LL::cmd_setattr();
150 break;
151 case LL_CR_ACCESS:
152 LL::cmd_access();
153 break;
154 case LL_CR_LOOKUP:
155 LL::cmd_lookup();
156 break;
157 case LL_CR_CREATE:
158 LL::cmd_create();
159 break;
160 case LL_CR_REMOVE:
161 LL::cmd_remove();
162 break;
163 case LL_CR_RENAME:
164 LL::cmd_rename();
165 break;
166 case LL_CR_MKDIR:
167 LL::cmd_mkdir();
168 break;
169 case LL_CR_RMDIR:
170 LL::cmd_rmdir();
171 break;
172 case LL_CR_READDIR:
173 LL::cmd_readdir();
174 break;
175 case LL_CR_SYMLINK:
176 LL::cmd_symlink();
177 break;
178 case LL_CR_READLINK:
179 LL::cmd_readlink();
180 break;
181 default:
182 ui->error(
183 "%s: control register: invalid command: %d\n", getName(),
184 sp->reg_cr);
185 sp->reg_ecr = ENOTSUP;
186 break;
187 }
188}
189
190void LL::wr_arg_addr(uint32_t val)
191{
192 sp->reg_arg_addr = val;
193}
194
195void LL::wr_res_addr(uint32_t val)
196{
197 sp->reg_res_addr = val;
198}
199
200void LL::cmd_read()
201{
202 ll_read_arg_t arg;
203 ll_read_res_t res;
204 int fd;
205#ifdef LL_CRC
206 uint32_t crc = 0;
207#endif
208
209 if (ll_trace) ui->output(
210 "%s: LL::cmd_read\n", getName());
211
212 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_read_arg_t));
213
214 if (ll_trace) ui->output(
215 " path=%s offset=%lld count=%d\n", arg.fh.path, arg.offset,
216 arg.count);
217
218 if ((fd = open(arg.fh.path, O_RDONLY | O_LARGEFILE)) == -1) {
219 if (ll_trace) ui->output(
220 " open(%s) failed (%d)\n", arg.fh.path, errno);
221 sp->reg_ecr = errno;
222 return;
223 }
224
225 if ((res.count = (uint32_t)pread(fd, res.buf, arg.count,
226 arg.offset)) == -1) {
227 if (ll_trace) ui->output(
228 " pread(%s, %lld, %d) failed (%d)\n", arg.fh.path,
229 arg.offset, arg.count, errno);
230 sp->reg_ecr = errno;
231 return;
232 }
233
234 close(fd);
235
236#ifdef LL_CRC
237 LL::crc(&crc, res.buf, res.count);
238 if (ll_trace) ui->output(
239 " returning count=%d (crc=%x)\n", res.count, crc);
240#else
241 if (ll_trace) ui->output(
242 " returning count=%d\n", res.count);
243#endif
244
245 LL::dma_out(sp->reg_res_addr, &res, sizeof(ll_read_res_t));
246}
247
248void LL::cmd_write()
249{
250 ll_write_arg_t arg;
251 ll_write_res_t res;
252 mode_t omode = 0;
253 int fd;
254#ifdef LL_CRC
255 uint32_t crc = 0;
256#endif
257
258 if (ll_trace) ui->output(
259 "%s: LL::cmd_write\n", getName());
260
261 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_write_arg_t));
262
263#ifdef LL_CRC
264 LL::crc(&crc, arg.buf, arg.count);
265 if (ll_trace) ui->output(
266 " path=%s offset=%lld count=%d (crc=%x)\n", arg.fh.path,
267 arg.offset, arg.count, crc);
268#else
269 if (ll_trace) ui->output(
270 " path=%s offset=%lld count=%d\n", arg.fh.path,
271 arg.offset, arg.count);
272#endif
273
274 /*
275 * This is a hack to allow writes to files created with read only
276 * permission.
277 */
278 if (access(arg.fh.path, W_OK) == -1) {
279 struct stat s;
280
281 if (stat(arg.fh.path, &s) == -1) {
282 if (ll_trace) ui->output(
283 " stat(%s) failed (%d)\n", arg.fh.path, errno);
284 sp->reg_ecr = errno;
285 return;
286 }
287 if (s.st_uid == getuid()) {
288 /* We own this file, so go ahead an add write
289 * permission. */
290 omode = s.st_mode;
291 (void) chmod(arg.fh.path, 0600);
292 }
293 }
294
295 if ((fd = open(arg.fh.path, O_WRONLY | O_LARGEFILE)) == -1) {
296 if (ll_trace) ui->output(
297 " open(%s) failed (%d)\n", arg.fh.path, errno);
298 sp->reg_ecr = errno;
299 if (omode != 0)
300 (void) chmod(arg.fh.path, omode);
301 return;
302 }
303
304 if ((res.count = (uint32_t)pwrite(fd, arg.buf, arg.count,
305 arg.offset)) == -1) {
306 if (ll_trace) ui->output(
307 " write(%s, %lld, %d) failed (%d)\n", arg.fh.path,
308 arg.offset, arg.count, errno);
309 sp->reg_ecr = errno;
310 if (omode != 0)
311 (void) chmod(arg.fh.path, omode);
312 return;
313 }
314
315 close(fd);
316
317 /* Restore the previous permission if we modified it. */
318 if (omode != 0)
319 (void) chmod(arg.fh.path, omode);
320
321 if (ll_trace) ui->output(
322 " returning count=%d\n", res.count);
323
324 LL::dma_out(sp->reg_res_addr, &res, sizeof(ll_write_res_t));
325}
326
327void LL::cmd_getattr()
328{
329 ll_getattr_arg_t arg;
330 ll_getattr_res_t res;
331 struct stat s;
332 uint64_t ino_tmp;
333
334 if (ll_trace) ui->output(
335 "%s: LL::cmd_getattr\n", getName());
336
337 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_getattr_arg_t));
338
339 if (ll_trace) ui->output(
340 " path=%s\n", arg.fh.path);
341
342 if (lstat(arg.fh.path, &s) == -1) {
343 if (ll_trace) ui->output(
344 " lstat(%s) failed (%d)\n", arg.fh.path, errno);
345 sp->reg_ecr = errno;
346 return;
347 }
348
349 switch (s.st_mode & S_IFMT) {
350 case S_IFREG: res.attr.type = LL_TYPE_REG; break;
351 case S_IFDIR: res.attr.type = LL_TYPE_DIR; break;
352 case S_IFLNK: res.attr.type = LL_TYPE_LNK; break;
353 default: res.attr.type = LL_TYPE_BAD;
354 }
355
356 res.attr.mode = s.st_mode & S_IAMB;
357 res.attr.nlink = s.st_nlink;
358 res.attr.uid = s.st_uid;
359 res.attr.gid = s.st_gid;
360 res.attr.size = s.st_size;
361 res.attr.atime = (int32_t)s.st_atime; /* XXX - trunc in 64-bit mode */
362 res.attr.mtime = (int32_t)s.st_mtime; /* XXX - trunc in 64-bit mode */
363 res.attr.ctime = (int32_t)s.st_ctime; /* XXX - trunc in 64-bit mode */
364
365 ino_tmp = ((uint64_t)s.st_dev<<32)^s.st_ino;
366 LL::crc(&res.attr.ino, (uchar_t *)&ino_tmp, sizeof(uint64_t));
367
368 if (ll_trace) ui->output(
369 " returning type=%d mode=0x%x nlink=%d uid=%d gid=%d"
370 " size=%lld ino=%x\n",
371 res.attr.type, res.attr.mode, res.attr.nlink, res.attr.uid,
372 res.attr.gid, res.attr.size, res.attr.ino);
373
374 LL::dma_out(sp->reg_res_addr, &res, sizeof(ll_getattr_res_t));
375}
376
377void LL::cmd_setattr()
378{
379 ll_setattr_arg_t arg;
380
381 if (ll_trace) ui->output(
382 "%s: LL::cmd_setattr\n", getName());
383
384 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_setattr_arg_t));
385
386 if (ll_trace) ui->output(
387 " path=%s mask=0x%x\n", arg.fh.path, arg.mask);
388
389 if (arg.mask & LL_MASK_MODE) {
390 if (ll_trace) ui->output(
391 " mode=0x%x\n", arg.attr.mode);
392 if (chmod(arg.fh.path, arg.attr.mode) == -1) {
393 if (ll_trace) ui->output(
394 " chmod(%s, 0x%x) failed (%d)\n", arg.fh.path,
395 arg.attr.mode, errno);
396 sp->reg_ecr = errno;
397 return;
398 }
399 }
400
401 if (arg.mask & (LL_MASK_UID | LL_MASK_GID)) {
402 if (arg.mask & LL_MASK_UID) {
403 if (ll_trace) ui->output(
404 " uid=%d\n", arg.attr.uid);
405 if (lchown(arg.fh.path, arg.attr.uid, -1) == -1) {
406 if (ll_trace) ui->output(
407 " lchown(%s, %d, -1) failed (%d)\n",
408 arg.fh.path, arg.attr.uid, errno);
409 sp->reg_ecr = errno;
410 return;
411 }
412 }
413 if (arg.mask & LL_MASK_GID) {
414 if (ll_trace) ui->output(
415 " gid=%d\n", arg.attr.gid);
416 if (lchown(arg.fh.path, -1, arg.attr.gid) == -1) {
417 if (ll_trace) ui->output(
418 " lchown(%s, -1, %d) failed (%d)\n",
419 arg.fh.path, arg.attr.gid, errno);
420 sp->reg_ecr = errno;
421 return;
422 }
423 }
424 }
425
426 if (arg.mask & (LL_MASK_ATIME | LL_MASK_MTIME)) {
427 struct utimbuf times;
428
429 if (arg.mask & (LL_MASK_ATIME | LL_MASK_MTIME)) {
430 if (ll_trace) ui->output(
431 " atime & mtime\n");
432 times.actime = arg.attr.atime;
433 times.modtime = arg.attr.mtime;
434 } else {
435 struct stat s;
436
437 if (lstat(arg.fh.path, &s) == -1) {
438 if (ll_trace) ui->output(
439 " lstat(%s) failed (%d)\n", arg.fh.path,
440 errno);
441 sp->reg_ecr = errno;
442 return;
443 }
444 if (arg.mask & LL_MASK_ATIME) {
445 if (ll_trace) ui->output(" atime\n");
446 times.actime = arg.attr.atime;
447 times.modtime = s.st_mtime;
448 }
449 if (arg.mask & LL_MASK_MTIME) {
450 if (ll_trace) ui->output(" mtime\n");
451 times.actime = s.st_atime;
452 times.modtime = arg.attr.mtime;
453 }
454 }
455 if (utime(arg.fh.path, &times) == -1) {
456 if (ll_trace) ui->output(
457 " utime(%s) failed (%d)\n", arg.fh.path, errno);
458 sp->reg_ecr = errno;
459 return;
460 }
461
462 }
463
464 if (arg.mask & LL_MASK_SIZE) {
465 if (ll_trace) ui->output(
466 " size=%lld\n", arg.attr.size);
467 if (truncate(arg.fh.path, arg.attr.size) == -1) {
468 if (ll_trace) ui->output(
469 " truncate(%s, %lld) failed (%d)\n", arg.fh.path,
470 arg.attr.size, errno);
471 sp->reg_ecr = errno;
472 return;
473 }
474 }
475}
476
477void LL::cmd_access()
478{
479 ll_access_arg_t arg;
480 int amode;
481
482 if (ll_trace) ui->output(
483 "%s: LL::cmd_access\n", getName());
484
485 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_access_arg_t));
486
487 if (ll_trace) ui->output(
488 " path=%s\n", arg.fh.path);
489
490 amode = 0;
491 if (arg.amode & LL_AMODE_READ) amode |= R_OK;
492 if (arg.amode & LL_AMODE_WRITE) amode |= W_OK;
493 if (arg.amode & LL_AMODE_EXEC) amode |= X_OK;
494
495 if (access(arg.fh.path, amode) == -1) {
496 if (ll_trace) ui->output(
497 " access(%s, 0x%x) failed (%d)\n", arg.fh.path, amode,
498 errno);
499 sp->reg_ecr = errno;
500 return;
501 }
502}
503
504void LL::cmd_lookup()
505{
506 ll_lookup_arg_t arg;
507 ll_lookup_res_t res;
508 struct stat s;
509
510 if (ll_trace) ui->output(
511 "%s: LL::cmd_lookup\n", getName());
512
513 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_lookup_arg_t));
514
515 if (ll_trace) ui->output(
516 " dir=%s name=%s\n", arg.dir_fh.path, arg.name);
517
518 LL::path_canon(res.fh.path, arg.dir_fh.path, arg.name);
519
520 if (lstat(res.fh.path, &s) == -1) {
521 if (ll_trace) ui->output(
522 " lstat(%s) failed (%d)\n", res.fh.path, errno);
523 sp->reg_ecr = errno;
524 return;
525 }
526
527 switch (s.st_mode & S_IFMT) {
528 case S_IFREG: res.type = LL_TYPE_REG; break;
529 case S_IFDIR: res.type = LL_TYPE_DIR; break;
530 case S_IFLNK: res.type = LL_TYPE_LNK; break;
531 default: res.type = LL_TYPE_BAD;
532 }
533
534 if (ll_trace) ui->output(
535 " returning path=%s type=%d\n", res.fh.path, res.type);
536
537 LL::dma_out(sp->reg_res_addr, &res, sizeof(ll_lookup_res_t));
538}
539
540void LL::cmd_create()
541{
542 ll_create_arg_t arg;
543 ll_create_res_t res;
544 mode_t om;
545 int fd;
546
547 if (ll_trace) ui->output(
548 "%s: LL::cmd_create\n", getName());
549
550 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_create_arg_t));
551
552 if (ll_trace) ui->output(
553 " dir=%s name=%s mode=0x%x\n", arg.dir_fh.path, arg.name,
554 arg.mode);
555
556 LL::path_canon(res.fh.path, arg.dir_fh.path, arg.name);
557
558 om = umask(0);
559 if ((fd = creat(res.fh.path, arg.mode)) == -1) {
560 if (ll_trace) ui->output(
561 " creat(%s, 0x%x) failed (%d)\n", res.fh.path, arg.mode,
562 errno);
563 sp->reg_ecr = errno;
564 umask(om);
565 return;
566 }
567 close(fd);
568 umask(om);
569
570 if (ll_trace) ui->output(
571 " returning path=%s\n", res.fh.path);
572
573 LL::dma_out(sp->reg_res_addr, &res, sizeof(ll_create_res_t));
574}
575
576void LL::cmd_remove()
577{
578 ll_remove_arg_t arg;
579 char path[LL_MAXPATHLEN];
580
581 if (ll_trace) ui->output(
582 "%s: LL::cmd_remove\n", getName());
583
584 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_remove_arg_t));
585
586 if (ll_trace) ui->output(
587 " dir=%s name=%s\n", arg.dir_fh.path, arg.name);
588
589 LL::path_canon(path, arg.dir_fh.path, arg.name);
590
591 if (unlink(path) == -1) {
592 if (ll_trace) ui->output(
593 " unlink(%s) failed (%d)\n", path);
594 sp->reg_ecr = errno;
595 return;
596 }
597}
598
599void LL::cmd_rename()
600{
601 ll_rename_arg_t arg;
602 char opath[LL_MAXPATHLEN];
603 char npath[LL_MAXPATHLEN];
604
605 if (ll_trace) ui->output(
606 "%s: LL::cmd_rename\n", getName());
607
608 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_rename_arg_t));
609
610 if (ll_trace) ui->output(
611 " odir=%s oname=%s ndir=%s nname=%s\n", arg.odir_fh.path,
612 arg.oname, arg.ndir_fh.path, arg.nname);
613
614 LL::path_canon(opath, arg.odir_fh.path, arg.oname);
615 LL::path_canon(npath, arg.ndir_fh.path, arg.nname);
616
617 if (rename(opath, npath) == -1) {
618 if (ll_trace) ui->output(
619 " rename(%s, %s) failed (%d)\n", opath, npath);
620 sp->reg_ecr = errno;
621 return;
622 }
623}
624
625void LL::cmd_mkdir()
626{
627 ll_mkdir_arg_t arg;
628 ll_mkdir_res_t res;
629 mode_t om;
630
631 if (ll_trace) ui->output(
632 "%s: LL::cmd_mkdir\n", getName());
633
634 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_mkdir_arg_t));
635
636 if (ll_trace) ui->output(
637 " dir=%s name=%s mode=0x%x\n", arg.dir_fh.path, arg.name,
638 arg.mode);
639
640 LL::path_canon(res.fh.path, arg.dir_fh.path, arg.name);
641
642 om = umask(0);
643 if (mkdir(res.fh.path, arg.mode) == -1) {
644 if (ll_trace) ui->output(
645 " mkdir(%s, 0x%x) failed (%d)\n", res.fh.path, arg.mode,
646 errno);
647 sp->reg_ecr = errno;
648 umask(om);
649 return;
650 }
651 umask(om);
652
653 if (ll_trace) ui->output(
654 " returning path=%s\n", res.fh.path);
655
656 LL::dma_out(sp->reg_res_addr, &res, sizeof(ll_mkdir_res_t));
657}
658
659void LL::cmd_rmdir()
660{
661 ll_rmdir_arg_t arg;
662 char path[LL_MAXPATHLEN];
663
664 if (ll_trace) ui->output(
665 "%s: LL::cmd_rmdir\n", getName());
666
667 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_rmdir_arg_t));
668
669 if (ll_trace) ui->output(
670 " dir=%s name=%s\n", arg.dir_fh.path, arg.name);
671
672 LL::path_canon(path, arg.dir_fh.path, arg.name);
673
674 if (rmdir(path) == -1) {
675 if (ll_trace) ui->output(
676 " rmdir(%s) failed (%d)\n", path, errno);
677 sp->reg_ecr = errno;
678 return;
679 }
680}
681
682void LL::cmd_readdir()
683{
684 ll_readdir_arg_t arg;
685 ll_readdir_res_t res;
686 struct ll_readdir_ent *rde;
687 struct ll_rdce *rdce;
688 int count, bufoff, reclen;
689
690 if (ll_trace) ui->output(
691 "%s: LL::cmd_readdir\n", getName());
692
693 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_readdir_arg_t));
694
695 if (ll_trace) ui->output(
696 " path=%s offset=%lld\n", arg.fh.path, arg.offset);
697
698 if (arg.offset == 0) {
699 /* First time - initialize readdir cache */
700 if (LL::rdc_init(&arg.fh)) {
701 sp->reg_ecr = errno;
702 return;
703 }
704
705 rdce = LL::rdce_head;
706 } else {
707 /* Skip ahead */
708 for (count = 0, rdce = LL::rdce_head;
709 count < arg.offset && rdce != NULL;
710 count++, rdce = rdce->next)
711 ;
712 }
713
714 bufoff = 0;
715 res.entries = 0;
716
717 while (rdce) {
718 reclen = (int)strlen(rdce->name) + 1;
719 reclen +=(int) sizeof(struct ll_readdir_ent);
720
721 /* Force 64-bit alignment */
722 reclen = (reclen + 7) & ~7;
723
724 if (reclen > (LL_DB_XFER_SIZE - bufoff))
725 break;
726
727 rde = (struct ll_readdir_ent *)&res.buf[bufoff];
728 rde->reclen = reclen;
729 rde->ino = rdce->ino;
730 strcpy(rde->name, rdce->name);
731
732 bufoff += reclen;
733 res.entries++;
734
735 rdce = rdce->next;
736
737 if (ll_trace) ui->output(
738 " name=%s ino=0x%x\n", rde->name, rde->ino);
739 }
740
741 if (ll_trace) ui->output(
742 " returning entries=%d\n", res.entries);
743
744 LL::dma_out(sp->reg_res_addr, &res, sizeof(ll_readdir_res_t));
745}
746
747void LL::cmd_symlink()
748{
749 ll_symlink_arg_t arg;
750 char cwd[LL_MAXPATHLEN];
751
752 if (ll_trace) ui->output(
753 "%s: LL::cmd_symlink\n", getName());
754
755 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_symlink_arg_t));
756
757 if (ll_trace) ui->output(
758 " dir=%s lname=%s tname=%s\n", arg.dir_fh.path, arg.lname,
759 arg.tname);
760
761 if (getcwd(cwd, LL_MAXPATHLEN) == NULL) {
762 if (ll_trace) ui->output(
763 " getcwd() failed (%d)\n", errno);
764 sp->reg_ecr = errno;
765 return;
766 }
767 if (chdir(arg.dir_fh.path) == -1) {
768 if (ll_trace) ui->output(
769 " chdir(%s) failed (%d)\n", arg.dir_fh.path, errno);
770 sp->reg_ecr = errno;
771 (void) chdir(cwd);
772 return;
773 }
774 if (symlink(arg.tname, arg.lname) == -1) {
775 if (ll_trace) ui->output(
776 " symlink(%s, %s) failed (%d)\n", arg.tname, arg.lname,
777 errno);
778 sp->reg_ecr = errno;
779 (void) chdir(cwd);
780 return;
781 }
782 (void) chdir(cwd);
783}
784
785void LL::cmd_readlink()
786{
787 ll_readlink_arg_t arg;
788 ll_readlink_res_t res;
789 int len;
790
791 if (ll_trace) ui->output(
792 "%s: LL::cmd_readlink\n", getName());
793
794 LL::dma_in(sp->reg_arg_addr, &arg, sizeof(ll_readlink_arg_t));
795
796 if (ll_trace) ui->output(
797 " link=%s\n", arg.fh.path);
798
799 if ((len = readlink(arg.fh.path, res.path, LL_MAXPATHLEN)) == -1) {
800 if (ll_trace) ui->output(
801 " readlink(%s) failed (%d)\n", arg.fh.path, errno);
802 sp->reg_ecr = errno;
803 return;
804 }
805 res.path[len] = '\0';
806
807 if (ll_trace) ui->output(
808 " returning path=%s\n", res.path);
809
810 LL::dma_out(sp->reg_res_addr, &res, sizeof(ll_readlink_res_t));
811}
812
813void LL::path_canon(char *canonpath, const char *path, const char *name)
814{
815 size_t len;
816
817 strcpy(canonpath, path);
818
819 if (strncmp(name, "..", MIN(strlen(name), 2)) == 0) {
820 /* handle ".." case */
821 len = strlen(canonpath);
822 while (len > 1 && (canonpath[len] != '/'))
823 len--;
824 canonpath[len] = '\0';
825 return;
826 }
827
828 /* append "/" to the directory name if not at root */
829 if ((len = strlen(canonpath)) && canonpath[len-1] != '/') {
830 strcat(canonpath, "/");
831 }
832
833 /* tack on the name */
834 strcat(canonpath, name);
835}
836
837int LL::rdc_init(struct ll_fhandle *fhp)
838{
839 struct ll_rdce *rdce, *tmp;
840 DIR *dirp;
841 char buf[PATH_MAX + 1 + sizeof(struct dirent)];
842 struct dirent *dp, *retdp;
843
844 for (rdce = LL::rdce_head; rdce != NULL; ) {
845 tmp = rdce->next;
846 free(rdce);
847 rdce = tmp;
848 }
849 LL::rdce_tail = LL::rdce_head = NULL;
850
851 if ((dirp = opendir(fhp->path)) == NULL) {
852 if (ll_trace) ui->output(
853 " opendir(%s) failed (%d)\n", fhp->path, errno);
854 return (errno);
855 }
856
857 dp = (struct dirent *)buf;
858 errno = 0;
859 while ((readdir_r(dirp, dp, &retdp) >= 0) && retdp != NULL) {
860 char path[LL_MAXPATHLEN];
861 struct stat s;
862 uint64_t ino_tmp;
863
864 rdce = (struct ll_rdce *)calloc(1, sizeof(struct ll_rdce));
865
866 LL::path_canon(path, fhp->path, dp->d_name);
867 if (lstat(path, &s) == -1) {
868 if (ll_trace) ui->output(
869 " lstat(%s) failed (%d)\n", path, errno);
870 return (errno);
871 }
872 ino_tmp = ((uint64_t)s.st_dev<<32)^s.st_ino;
873 LL::crc(&rdce->ino, (uchar_t *)&ino_tmp, sizeof(uint64_t));
874
875 strcpy(rdce->name, dp->d_name);
876
877 if (LL::rdce_head == NULL) {
878 LL::rdce_head = rdce;
879 } else {
880 rdce->prev = LL::rdce_tail;
881 LL::rdce_tail->next = rdce;
882 }
883 LL::rdce_tail = rdce;
884 }
885
886 if (errno) {
887 int e = errno;
888 if (ll_trace) ui->output(
889 " readdir_r() failed (%d)\n", e);
890 closedir(dirp);
891 return (e);
892 }
893
894 closedir(dirp);
895
896 return (0);
897}
898
899void LL::dma_in(uint64_t vaddr, void *data, long count)
900{
901 //dev_dma_in(vaddr, data, count);
902 pciMaster_dma(false,vaddr, data, count);
903}
904
905void LL::dma_out(uint64_t vaddr, void *data, long count)
906{
907 //dev_dma_out(vaddr, data, count);
908 pciMaster_dma(true,vaddr, data, count);
909}
910
911
912
913/*
914 * LL::crc -- compute 32 bit CRC -- ripped from ON cksum.c
915 *
916 * This is a 32 bit CRC with polynomial
917 * x**32 + x**26 + x**23 + x**22 + x**16 + x**12 + x**11 + x**10 +
918 * x**8 + x**7 + x**5 + x**4 + x**2 + x**1 + x**0
919 */
920static uint32_t crctab[256] = {
921 0x00000000,
922 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
923 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
924 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
925 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
926 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
927 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
928 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
929 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
930 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
931 0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
932 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
933 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
934 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
935 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
936 0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
937 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
938 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
939 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
940 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
941 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
942 0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
943 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
944 0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
945 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
946 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
947 0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
948 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
949 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
950 0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
951 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
952 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
953 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
954 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
955 0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
956 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
957 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
958 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
959 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
960 0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
961 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
962 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
963 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
964 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
965 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
966 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
967 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
968 0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
969 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
970 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
971 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
972 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
973};
974
975/*
976 * LL::crc -- compute 32 bit CRC
977 */
978void LL::crc(uint32_t *crcp, uchar_t *bp, size_t n)
979{
980 *crcp = 0;
981
982 while (n-- > 0)
983 *crcp = (*crcp<<8) ^ crctab[(uchar_t)((*crcp>>24)^*bp++)];
984}
985
986/////////////////////////////////////////////////////////
987
988bool LL::dump (FILE *fp)
989{
990 if (fwrite(sp, sizeof(ll_structT), 1, fp) != 1) {
991 return FALSE;
992 }
993 return genericPciDev::dump(DR_get_dir(),getName());
994}
995
996bool LL::restore (FILE *fp)
997{
998 if (fread(sp, sizeof(ll_structT), 1, fp) != 1) {
999 return FALSE;
1000 }
1001 if (restore_v5_dump())
1002 return genericPciDev::restore(DR_get_dir(),getName());
1003 else
1004 return true;
1005}
1006