1 /* $OpenBSD: promdev.c,v 1.2 1999/01/11 05:12:00 millert Exp $ */
2 /* $NetBSD: promdev.c,v 1.16 1995/11/14 15:04:01 pk Exp $ */
5 * Copyright (c) 1993 Paul Kranenburg
6 * Copyright (c) 1995 Gordon W. Ross
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Paul Kranenburg.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * Note: the `#ifndef BOOTXX' in here serve to queeze the code size
37 * of the 1st-stage boot program.
39 #include <sys/param.h>
40 #include <sys/reboot.h>
41 #include <machine/idprom.h>
42 #include <machine/oldmon.h>
43 #include <machine/ctlreg.h>
49 /* u_long _randseed = 1; */
52 int obp_close
__P((struct open_file
*));
53 int obp_strategy
__P((void *, int, daddr_t
, size_t, void *, size_t *));
54 ssize_t obp_xmit
__P((struct promdata
*, void *, size_t));
55 ssize_t obp_recv
__P((struct promdata
*, void *, size_t));
56 int prom0_close
__P((struct open_file
*));
57 int prom0_strategy
__P((void *, int, daddr_t
, size_t, void *, size_t *));
58 void prom0_iclose
__P((struct saioreq
*));
59 int prom0_iopen
__P((struct promdata
*));
60 ssize_t prom0_xmit
__P((struct promdata
*, void *, size_t));
61 ssize_t prom0_recv
__P((struct promdata
*, void *, size_t));
63 static char *prom_mapin
__P((u_long
, int, int));
65 int getdevtype
__P((int, char *));
66 int getprop
__P((int, char *, void *, int));
67 char *getpropstring
__P((int, char *));
69 static void prom0_fake
__P((void));
71 extern struct filesystem file_system_nfs
[];
72 extern struct filesystem file_system_cd9660
[];
73 extern struct filesystem file_system_ufs
[];
75 int prom_open
__P((struct open_file
*f
, ...)) { return 0; }
76 int prom_ioctl
__P((struct open_file
*f
, u_long c
, void *d
)) { return EIO
; }
78 struct devsw devsw
[] = {
79 { "prom0", prom0_strategy
, prom_open
, prom0_close
, prom_ioctl
},
80 { "prom", obp_strategy
, prom_open
, obp_close
, prom_ioctl
}
83 int ndevs
= (sizeof(devsw
)/sizeof(devsw
[0]));
85 char *prom_bootdevice
;
89 struct promvec
*promvec
;
95 register char *ap
, *cp
, *dp
;
97 if (cputyp
== CPU_SUN4
)
100 if (promvec
->pv_romvec_vers
>= 2) {
101 static char filestore
[16];
103 prom_bootdevice
= *promvec
->pv_v2bootargs
.v2_bootpath
;
106 cp
= *promvec
->pv_v2bootargs
.v2_bootargs
;
107 dp
= prom_bootfile
= filestore
;
108 while (*cp
&& *cp
!= '-')
110 while (dp
> prom_bootfile
&& *--dp
== ' ');
115 static char bootstore
[16];
116 dp
= prom_bootdevice
= bootstore
;
117 cp
= (*promvec
->pv_v0bootargs
)->ba_argv
[0];
125 prom_bootfile
= (*promvec
->pv_v0bootargs
)->ba_kernel
;
126 ap
= (*promvec
->pv_v0bootargs
)->ba_argv
[1];
131 if (ap
== NULL
|| *ap
!= '-')
137 prom_boothow
|= RB_ASKNAME
;
140 prom_boothow
|= RB_SINGLE
;
143 prom_boothow
|= RB_KDB
;
152 devopen(f
, fname
, file
)
160 pd
= (struct promdata
*)alloc(sizeof *pd
);
162 if (cputyp
== CPU_SUN4
) {
163 error
= prom0_iopen(pd
);
165 pd
->xmit
= prom0_xmit
;
166 pd
->recv
= prom0_recv
;
169 fd
= (promvec
->pv_romvec_vers
>= 2)
170 ? (*promvec
->pv_v2devops
.v2_open
)(prom_bootdevice
)
171 : (*promvec
->pv_v0devops
.v0_open
)(prom_bootdevice
);
184 printf("Can't open device `%s'\n", prom_bootdevice
);
189 pd
->devtype
= DT_BLOCK
;
191 pd
->devtype
= getdevtype(fd
, prom_bootdevice
);
192 /* Assume type BYTE is a raw device */
193 if (pd
->devtype
!= DT_BYTE
)
194 *file
= (char *)fname
;
196 if (pd
->devtype
== DT_NET
) {
197 bcopy(file_system_nfs
, file_system
, sizeof(struct fs_ops
));
198 if ((error
= net_open(pd
)) != 0) {
199 printf("Can't open network device `%s'\n",
204 bcopy(file_system_ufs
, file_system
, sizeof(struct fs_ops
));
205 bcopy(&file_system_cd9660
, file_system
+ 1, sizeof file_system
[0]);
210 f
->f_dev
= &devsw
[cputyp
== CPU_SUN4
? 0 : 1];
211 f
->f_devdata
= (void *)pd
;
216 obp_strategy(devdata
, flag
, dblk
, size
, buf
, rsize
)
225 struct promdata
*pd
= (struct promdata
*)devdata
;
229 printf("promstrategy: size=%d dblk=%d\n", size
, dblk
);
232 if (promvec
->pv_romvec_vers
>= 2) {
233 if (pd
->devtype
== DT_BLOCK
)
234 (*promvec
->pv_v2devops
.v2_seek
)(fd
, 0, dbtob(dblk
));
236 *rsize
= (*((flag
== F_READ
)
237 ? (u_int (*)())promvec
->pv_v2devops
.v2_read
238 : (u_int (*)())promvec
->pv_v2devops
.v2_write
241 int n
= (*((flag
== F_READ
)
242 ? (u_int (*)())promvec
->pv_v0devops
.v0_rbdev
243 : (u_int (*)())promvec
->pv_v0devops
.v0_wbdev
244 ))(fd
, btodb(size
), dblk
, buf
);
249 printf("rsize = %x\n", *rsize
);
255 * On old-monitor machines, things work differently.
258 prom0_strategy(devdata
, flag
, dblk
, size
, buf
, rsize
)
266 struct promdata
*pd
= devdata
;
268 struct om_boottable
*ops
;
274 ops
= si
->si_boottab
;
277 printf("prom_strategy: size=%d dblk=%d\n", size
, dblk
);
280 dmabuf
= dvma_mapin(buf
, size
);
286 si_flag
= (flag
== F_READ
) ? SAIO_F_READ
: SAIO_F_WRITE
;
287 xcnt
= (*ops
->b_strategy
)(si
, si_flag
);
288 dvma_mapout(dmabuf
, size
);
291 printf("disk_strategy: xcnt = %x\n", xcnt
);
305 struct promdata
*pd
= f
->f_devdata
;
306 register int fd
= pd
->fd
;
309 if (pd
->devtype
== DT_NET
)
312 if (promvec
->pv_romvec_vers
>= 2)
313 (void)(*promvec
->pv_v2devops
.v2_close
)(fd
);
315 (void)(*promvec
->pv_v0devops
.v0_close
)(fd
);
323 struct promdata
*pd
= f
->f_devdata
;
326 if (pd
->devtype
== DT_NET
)
329 prom0_iclose(pd
->si
);
331 *romp
->echo
= saveecho
; /* Hmm, probably must go somewhere else */
337 obp_xmit(pd
, buf
, len
)
342 return (promvec
->pv_romvec_vers
>= 2
343 ? (*promvec
->pv_v2devops
.v2_write
)(pd
->fd
, buf
, len
)
344 : (*promvec
->pv_v0devops
.v0_wnet
)(pd
->fd
, len
, buf
));
348 obp_recv(pd
, buf
, len
)
355 n
= (promvec
->pv_romvec_vers
>= 2
356 ? (*promvec
->pv_v2devops
.v2_read
)(pd
->fd
, buf
, len
)
357 : (*promvec
->pv_v0devops
.v0_rnet
)(pd
->fd
, len
, buf
));
358 return (n
== -2 ? 0 : n
);
362 prom0_xmit(pd
, buf
, len
)
375 printf("xmit: not a network device\n");
378 dmabuf
= dvma_mapin(buf
, len
);
379 rv
= sif
->sif_xmit(si
->si_devdata
, dmabuf
, len
);
380 dvma_mapout(dmabuf
, len
);
382 return (ssize_t
)(rv
? -1 : len
);
386 prom0_recv(pd
, buf
, len
)
398 dmabuf
= dvma_mapin(buf
, len
);
399 rv
= sif
->sif_poll(si
->si_devdata
, dmabuf
);
400 dvma_mapout(dmabuf
, len
);
411 if (promvec
->pv_romvec_vers
> 2)
412 while ((n
= (*promvec
->pv_v2devops
.v2_read
)
413 (*promvec
->pv_v2bootargs
.v2_fd0
, (caddr_t
)&c
, 1)) != 1);
415 c
= (*promvec
->pv_getchar
)();
434 if (promvec
->pv_romvec_vers
> 2) {
435 n
= (*promvec
->pv_v2devops
.v2_read
)
436 (*promvec
->pv_v2bootargs
.v2_fd0
, (caddr_t
)&c
, 1);
440 c
= (*promvec
->pv_nbgetchar
)();
454 if (promvec
->pv_romvec_vers
> 2)
455 (*promvec
->pv_v2devops
.v2_write
)
456 (*promvec
->pv_v2bootargs
.v2_fd1
, &c0
, 1);
458 (*promvec
->pv_putchar
)(c
);
483 register int ticks
= getticks();
484 return ((time_t)(ticks
/ hz
));
490 if (promvec
->pv_romvec_vers
>= 2) {
492 (void)(*promvec
->pv_v2devops
.v2_read
)
493 (*promvec
->pv_v2bootargs
.v2_fd0
, (caddr_t
)&c
, 0);
495 (void)(*promvec
->pv_nbgetchar
)();
497 return *(promvec
->pv_ticks
);
501 prom_getether(fd
, ea
)
504 if (cputyp
== CPU_SUN4
) {
505 static struct idprom sun4_idprom
;
509 if (sun4_idprom
.id_format
== 0) {
510 dst
= (char*)&sun4_idprom
;
511 src
= (char*)AC_IDPROM
;
512 len
= sizeof(struct idprom
);
514 x
= lduba(src
++, ASI_CONTROL
);
518 bcopy(sun4_idprom
.id_ether
, ea
, 6);
519 } else if (promvec
->pv_romvec_vers
<= 2) {
520 (void)(*promvec
->pv_enaddr
)(fd
, (char *)ea
);
523 sprintf(buf
, "%x mac-address drop swap 6 cmove", ea
);
524 promvec
->pv_fortheval
.v2_eval(buf
);
530 * A number of well-known devices on sun4s.
551 if (promvec
->pv_romvec_vers
>= 2) {
552 int node
= (*promvec
->pv_v2devops
.v2_fd_phandle
)(fd
);
553 char *cp
= getpropstring(node
, "device_type");
554 if (strcmp(cp
, "block") == 0)
556 else if (strcmp(cp
, "network") == 0)
558 else if (strcmp(cp
, "byte") == 0)
562 for (dp
= dtab
; dp
->name
; dp
++) {
563 if (name
[0] == dp
->name
[0] &&
564 name
[1] == dp
->name
[1])
572 * OpenPROM nodes & property routines (from <sparc/autoconf.c>).
575 getprop(node
, name
, buf
, bufsiz
)
581 register struct nodeops
*no
;
584 no
= promvec
->pv_nodeops
;
585 len
= no
->no_proplen(node
, name
);
587 printf("node %x property %s length %d > %d\n",
588 node
, name
, len
, bufsiz
);
591 no
->no_getprop(node
, name
, buf
);
596 * Return a string property. There is a (small) limit on the length;
597 * the string is fetched into a static buffer which is overwritten on
601 getpropstring(node
, name
)
606 static char stringbuf
[64];
608 len
= getprop(node
, name
, (void *)stringbuf
, sizeof stringbuf
- 1);
611 stringbuf
[len
] = '\0'; /* usually unnecessary */
617 * Old monitor routines
620 #include <machine/pte.h>
622 struct saioreq prom_si
;
623 static int promdev_inuse
;
629 struct om_bootparam
*bp
;
630 struct om_boottable
*ops
;
638 bp
= *romp
->bootParam
;
640 dip
= ops
->b_devinfo
;
643 printf("Boot device type: %s\n", ops
->b_desc
);
644 printf("d_devbytes=%d\n", dip
->d_devbytes
);
645 printf("d_dmabytes=%d\n", dip
->d_dmabytes
);
646 printf("d_localbytes=%d\n", dip
->d_localbytes
);
647 printf("d_stdcount=%d\n", dip
->d_stdcount
);
648 printf("d_stdaddrs[%d]=%x\n", bp
->ctlrNum
, dip
->d_stdaddrs
[bp
->ctlrNum
]);
649 printf("d_devtype=%d\n", dip
->d_devtype
);
650 printf("d_maxiobytes=%d\n", dip
->d_maxiobytes
);
656 bzero((caddr_t
)si
, sizeof(*si
));
657 si
->si_boottab
= ops
;
658 si
->si_ctlr
= bp
->ctlrNum
;
659 si
->si_unit
= bp
->unitNum
;
660 si
->si_boff
= bp
->partNum
;
662 if (si
->si_ctlr
> dip
->d_stdcount
) {
663 printf("Invalid controller number\n");
667 if (dip
->d_devbytes
) {
668 si
->si_devaddr
= prom_mapin(dip
->d_stdaddrs
[si
->si_ctlr
],
669 dip
->d_devbytes
, dip
->d_devtype
);
671 printf("prom_iopen: devaddr=0x%x pte=0x%x\n",
673 getpte((u_long
)si
->si_devaddr
& ~PGOFSET
));
677 if (dip
->d_dmabytes
) {
678 si
->si_dmaaddr
= dvma_alloc(dip
->d_dmabytes
);
680 printf("prom_iopen: dmaaddr=0x%x\n", si
->si_dmaaddr
);
684 if (dip
->d_localbytes
) {
685 si
->si_devdata
= alloc(dip
->d_localbytes
);
687 printf("prom_iopen: devdata=0x%x\n", si
->si_devdata
);
691 /* OK, call the PROM device open routine. */
692 error
= (*ops
->b_open
)(si
);
694 printf("prom_iopen: \"%s\" error=%d\n",
699 printf("prom_iopen: succeeded, error=%d\n", error
);
711 struct om_boottable
*ops
;
714 if (promdev_inuse
== 0)
717 ops
= si
->si_boottab
;
718 dip
= ops
->b_devinfo
;
722 if (si
->si_dmaaddr
) {
723 dvma_free(si
->si_dmaaddr
, dip
->d_dmabytes
);
724 si
->si_dmaaddr
= NULL
;
730 static struct mapinfo
{
735 { MAP_MAINMEM
, PG_OBMEM
, 0 },
736 { MAP_OBIO
, PG_OBIO
, 0 },
737 { MAP_MBMEM
, PG_VME16
, 0xFF000000 },
738 { MAP_MBIO
, PG_VME16
, 0xFFFF0000 },
739 { MAP_VME16A16D
, PG_VME16
, 0xFFFF0000 },
740 { MAP_VME16A32D
, PG_VME32
, 0xFFFF0000 },
741 { MAP_VME24A16D
, PG_VME16
, 0xFF000000 },
742 { MAP_VME24A32D
, PG_VME32
, 0xFF000000 },
743 { MAP_VME32A16D
, PG_VME16
, 0 },
744 { MAP_VME32A32D
, PG_VME32
, 0 },
746 static prom_mapinfo_cnt
= sizeof(prom_mapinfo
) / sizeof(prom_mapinfo
[0]);
748 /* The virtual address we will use for PROM device mappings. */
749 static u_long prom_devmap
= MONSHORTSEG
;
752 prom_mapin(physaddr
, length
, maptype
)
758 if (length
> (4*NBPG
))
759 panic("prom_mapin: length=%d", length
);
761 for (i
= 0; i
< prom_mapinfo_cnt
; i
++)
762 if (prom_mapinfo
[i
].maptype
== maptype
)
764 panic("prom_mapin: invalid maptype %d", maptype
);
767 pte
= prom_mapinfo
[i
].pgtype
;
768 pte
|= (PG_V
|PG_W
|PG_S
|PG_NC
);
769 pa
= prom_mapinfo
[i
].base
;
771 pte
|= ((pa
>> PGSHIFT
) & PG_PFNUM
);
779 } while (length
> 0);
780 return ((char*)(prom_devmap
| (pa
& PGOFSET
)));
786 static struct promvec promvecstore
;
788 promvec
= &promvecstore
;
790 promvec
->pv_stdin
= romp
->inSource
;
791 promvec
->pv_stdout
= romp
->outSink
;
792 promvec
->pv_putchar
= romp
->putChar
;
793 promvec
->pv_putstr
= romp
->fbWriteStr
;
794 promvec
->pv_nbgetchar
= romp
->mayGet
;
795 promvec
->pv_getchar
= romp
->getChar
;
796 promvec
->pv_romvec_vers
= 0; /* eek! */
797 promvec
->pv_reboot
= romp
->reBoot
;
798 promvec
->pv_abort
= romp
->abortEntry
;
799 promvec
->pv_setctxt
= romp
->setcxsegmap
;
800 promvec
->pv_v0bootargs
= (struct v0bootargs
**)(romp
->bootParam
);
801 promvec
->pv_halt
= romp
->exitToMon
;
802 promvec
->pv_ticks
= romp
->nmiClock
;
803 saveecho
= *romp
->echo
;