1 /*        $NetBSD: arcbios.c,v 1.19 2020/08/14 16:53:06 skrll Exp $   */
2 /*        $OpenBSD: arcbios.c,v 1.3 1998/06/06 06:33:33 mickey Exp $  */
3 
4 /*-
5  * Copyright (c) 1996 M. Warner Losh.  All rights reserved.
6  * Copyright (c) 1996, 1997, 1998 Per Fogelstrom.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: arcbios.c,v 1.19 2020/08/14 16:53:06 skrll Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 #include <sys/kcore.h>
40 #include <uvm/uvm_extern.h>
41 #include <dev/cons.h>
42 #include <machine/cpu.h>
43 #include <machine/regdef.h>
44 #include <arc/arc/arcbios.h>
45 
46 int Bios_Read(int, char *, int, int *);
47 int Bios_Write(int, char *, int, int *);
48 int Bios_Open(char *, int, u_int *);
49 int Bios_Close(u_int);
50 arc_mem_t *Bios_GetMemoryDescriptor(arc_mem_t *);
51 arc_sid_t *Bios_GetSystemId(void);
52 arc_config_t *Bios_GetChild(arc_config_t *);
53 arc_config_t *Bios_GetPeer(arc_config_t *);
54 arc_dsp_stat_t *Bios_GetDisplayStatus(int);
55 
56 static void bios_config_id_copy(arc_config_t *, char *, size_t);
57 static void bios_config_component(arc_config_t *);
58 static void bios_config_subtree(arc_config_t *);
59 
60 char arc_vendor_id[sizeof(((arc_sid_t *)0)->vendor) + 1];
61 unsigned char arc_product_id[sizeof(((arc_sid_t *)0)->prodid)];
62 
63 char arc_id[64 + 1];
64 
65 char arc_displayc_id[64 + 1];           /* DisplayController id */
66 arc_dsp_stat_t      arc_displayinfo;    /* Save area for display status info. */
67 
68 int arc_cpu_l2cache_size = 0;
69 
70 /*
71  *        BIOS based console, for early stage.
72  */
73 
74 int  biosgetc(dev_t);
75 void biosputc(dev_t, int);
76 
77 /* this is to fake out the console routines, while booting. */
78 struct consdev bioscons = {
79           NULL, NULL, biosgetc, biosputc, nullcnpollc, NULL, NULL,
80               NULL, NODEV, CN_DEAD
81 };
82 
83 int
biosgetc(dev_t dev)84 biosgetc(dev_t dev)
85 {
86           int cnt;
87           char buf;
88 
89           if (Bios_Read(0, &buf, 1, &cnt) != arc_ESUCCESS)
90                     return -1;
91           return buf & 255;
92 }
93 
94 void
biosputc(dev_t dev,int ch)95 biosputc(dev_t dev, int ch)
96 {
97           int cnt;
98           char buf;
99 
100           buf = ch;
101           Bios_Write(1, &buf, 1, &cnt);
102 }
103 
104 void
bios_init_console(void)105 bios_init_console(void)
106 {
107           static int initialized = 0;
108 
109           if (!initialized) {
110                     initialized = 1;
111                     /* fake out the console routines, for now */
112                     cn_tab = &bioscons;
113           }
114 }
115 
116 /*
117  * Get memory descriptor for the memory configuration and
118  * create a layout database used by pmap init to set up
119  * the memory system.
120  *
121  * Concatenate obvious adjecent segments.
122  */
123 int
bios_configure_memory(int * mem_reserved,phys_ram_seg_t * mem_clusters,int * mem_cluster_cnt_return)124 bios_configure_memory(int *mem_reserved, phys_ram_seg_t *mem_clusters,
125     int *mem_cluster_cnt_return)
126 {
127           int bios_physmem = 0;                   /* Total physical memory size */
128           int mem_cluster_cnt = 0;
129 
130           arc_mem_t *descr = NULL;
131           paddr_t seg_start, seg_end;
132           int i, reserved;
133 
134           while ((descr = Bios_GetMemoryDescriptor(descr)) != NULL) {
135                     seg_start = descr->BasePage * 4096;
136                     seg_end = seg_start + descr->PageCount * 4096;
137 
138 #ifdef BIOS_MEMORY_DEBUG
139                     printf("memory type:%d, 0x%8lx..%8lx, size:%8ld bytes\n",
140                         descr->Type, (u_long)seg_start, (u_long)seg_end,
141                         (u_long)(seg_end - seg_start));
142 #endif
143 
144                     switch (descr->Type) {
145                     case BadMemory:               /* Have no use for these */
146                               break;
147 
148                     case ExeceptionBlock:
149                     case SystemParameterBlock:
150                     case FirmwarePermanent:
151                               reserved = 1;
152                               goto account_it;
153 
154                     case FreeMemory:
155                     case LoadedProgram: /* This is the loaded kernel */
156                     case FirmwareTemporary:
157                     case FreeContigous:
158                               reserved = 0;
159 account_it:
160                               bios_physmem += descr->PageCount * 4096;
161 
162                               for (i = 0; i < mem_cluster_cnt; ) {
163                                         if (mem_reserved[i] == reserved &&
164                                             mem_clusters[i].start == seg_end)
165                                                   seg_end += mem_clusters[i].size;
166                                         else if (mem_reserved[i] == reserved &&
167                                             mem_clusters[i].start +
168                                             mem_clusters[i].size == seg_start)
169                                                   seg_start = mem_clusters[i].start;
170                                         else { /* do not merge the cluster */
171                                                   i++;
172                                                   continue;
173                                         }
174                                         --mem_cluster_cnt;
175                                         mem_reserved[i] = mem_reserved[mem_cluster_cnt];
176                                         mem_clusters[i] = mem_clusters[mem_cluster_cnt];
177                               }
178                               /* assert(i == mem_cluster_cnt); */
179                               if (mem_cluster_cnt >= VM_PHYSSEG_MAX) {
180                                         printf("VM_PHYSSEG_MAX too small\n");
181                                         for (;;)
182                                                   ;
183                               }
184                               mem_reserved[i] = reserved;
185                               mem_clusters[i].start =       seg_start;
186                               mem_clusters[i].size = seg_end - seg_start;
187                               mem_cluster_cnt++;
188                               break;
189 
190                     default:            /* Unknown type, leave it alone... */
191                               break;
192                     }
193           }
194 
195 #ifdef BIOS_MEMORY_DEBUG
196           for (i = 0; i < mem_cluster_cnt; i++)
197                     printf("mem_clusters[%d] = %d:{ 0x%8lx, 0x%8lx }\n", i,
198                         mem_reserved[i],
199                         (long)mem_clusters[i].start,
200                         (long)mem_clusters[i].size);
201           printf("physmem = %d\n", bios_physmem);
202 #endif
203 
204           *mem_cluster_cnt_return = mem_cluster_cnt;
205           return bios_physmem;
206 }
207 
208 /*
209  * ARC Firmware present?
210  */
211 int
bios_ident(void)212 bios_ident(void)
213 {
214 
215           return (ArcBiosBase->magic == ARC_PARAM_BLK_MAGIC) ||
216               (ArcBiosBase->magic == ARC_PARAM_BLK_MAGIC_BUG);
217 }
218 
219 /*
220  * save various information of BIOS for future use.
221  */
222 
223 static void
bios_config_id_copy(arc_config_t * cf,char * string,size_t size)224 bios_config_id_copy(arc_config_t *cf, char *string, size_t size)
225 {
226 
227           size--;
228           if (size > cf->id_len)
229                     size = cf->id_len;
230           memcpy(string, cf->id, size);
231           string[size] = '\0';
232 }
233 
234 static void
bios_config_component(arc_config_t * cf)235 bios_config_component(arc_config_t *cf)
236 {
237 
238           switch (cf->class) {
239           case arc_SystemClass:
240                     if (cf->type == arc_System)
241                               bios_config_id_copy(cf, arc_id, sizeof(arc_id));
242                     break;
243           case arc_CacheClass:
244                     if (cf->type == arc_SecondaryDcache)
245                               arc_cpu_l2cache_size = 4096 << (cf->key & 0xffff);
246                     break;
247           case arc_ControllerClass:
248                     if (cf->type == arc_DisplayController &&
249                         arc_displayc_id[0] == '\0' /* first found one. XXX */)
250                               bios_config_id_copy(cf, arc_displayc_id,
251                                   sizeof(arc_displayc_id));
252                     break;
253           default:
254                     break;
255           }
256 }
257 
258 static
bios_config_subtree(arc_config_t * cf)259 void bios_config_subtree(arc_config_t *cf)
260 {
261 
262           for (cf = Bios_GetChild(cf); cf != NULL; cf = Bios_GetPeer(cf)) {
263                     bios_config_component(cf);
264                     bios_config_subtree(cf);
265           }
266 }
267 
268 void
bios_save_info(void)269 bios_save_info(void)
270 {
271           arc_sid_t *sid;
272 
273           sid = Bios_GetSystemId();
274           if (sid) {
275                     memcpy(arc_vendor_id, sid->vendor, sizeof(arc_vendor_id) - 1);
276                     arc_vendor_id[sizeof(arc_vendor_id) - 1] = 0;
277                     memcpy(arc_product_id, sid->prodid, sizeof(arc_product_id));
278           }
279 
280           bios_config_subtree(NULL);
281 
282 #ifdef arc
283           arc_displayinfo = *Bios_GetDisplayStatus(1);
284 #endif
285 }
286 
287 #ifdef arc
288 /*
289  * Return geometry of the display. Used by pccons.c to set up the
290  * display configuration.
291  */
292 void
bios_display_info(int * xpos,int * ypos,int * xsize,int * ysize)293 bios_display_info(int *xpos, int *ypos, int *xsize, int *ysize)
294 {
295 
296           *xpos = arc_displayinfo.CursorXPosition;
297           *ypos = arc_displayinfo.CursorYPosition;
298           *xsize = arc_displayinfo.CursorMaxXPosition;
299           *ysize = arc_displayinfo.CursorMaxYPosition;
300 }
301 #endif
302