1 /*        $NetBSD: region.c,v 1.3 2009/01/18 09:46:59 lukem Exp $     */
2 
3 /*-
4  * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *        Id: region.c,v 1.14 2000/08/08 14:12:25 iwasaki Exp
29  *        $FreeBSD: src/usr.sbin/acpi/amldb/region.c,v 1.4 2000/11/19 13:29:43 kris Exp $
30  */
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: region.c,v 1.3 2009/01/18 09:46:59 lukem Exp $");
33 
34 /*
35  * Region I/O subroutine
36  */
37 
38 #include <sys/param.h>
39 #include <sys/queue.h>
40 
41 #include <acpi_common.h>
42 #include <aml/aml_amlmem.h>
43 #include <aml/aml_name.h>
44 #include <aml/aml_common.h>
45 #include <aml/aml_region.h>
46 
47 #include <assert.h>
48 #include <err.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <unistd.h>
53 
54 #include "debug.h"
55 
56 int       aml_debug_prompt_regoutput = 0;
57 int       aml_debug_prompt_reginput = 1;
58 
59 static void         aml_simulation_regload(const char *dumpfile);
60 
61 struct ACPIRegionContent {
62           TAILQ_ENTRY(ACPIRegionContent) links;
63           int                 regtype;
64           u_int32_t addr;
65           u_int8_t  value;
66 };
67 
68 TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent);
69 struct    ACPIRegionContentList RegionContentList;
70 
71 static int          aml_simulation_initialized = 0;
72 
73 static void
aml_simulation_init(void)74 aml_simulation_init(void)
75 {
76 
77           aml_simulation_initialized = 1;
78           TAILQ_INIT(&RegionContentList);
79           aml_simulation_regload("region.ini");
80 }
81 
82 static int
aml_simulate_regcontent_add(int regtype,u_int32_t addr,u_int8_t value)83 aml_simulate_regcontent_add(int regtype, u_int32_t addr, u_int8_t value)
84 {
85           struct    ACPIRegionContent *rc;
86 
87           rc = malloc(sizeof(struct ACPIRegionContent));
88           if (rc == NULL) {
89                     return (-1);        /* malloc fail */
90           }
91           rc->regtype = regtype;
92           rc->addr = addr;
93           rc->value = value;
94 
95           TAILQ_INSERT_TAIL(&RegionContentList, rc, links);
96           return (0);
97 }
98 
99 static int
aml_simulate_regcontent_read(int regtype,u_int32_t addr,u_int8_t * valuep)100 aml_simulate_regcontent_read(int regtype, u_int32_t addr, u_int8_t *valuep)
101 {
102           struct    ACPIRegionContent *rc;
103 
104           if (!aml_simulation_initialized) {
105                     aml_simulation_init();
106           }
107           TAILQ_FOREACH(rc, &RegionContentList, links) {
108                     if (rc->regtype == regtype && rc->addr == addr) {
109                               *valuep = rc->value;
110                               return (1);         /* found */
111                     }
112           }
113 
114           return (aml_simulate_regcontent_add(regtype, addr, 0));
115 }
116 
117 static int
aml_simulate_regcontent_write(int regtype,u_int32_t addr,u_int8_t * valuep)118 aml_simulate_regcontent_write(int regtype, u_int32_t addr, u_int8_t *valuep)
119 {
120           struct    ACPIRegionContent *rc;
121 
122           if (!aml_simulation_initialized) {
123                     aml_simulation_init();
124           }
125           TAILQ_FOREACH(rc, &RegionContentList, links) {
126                     if (rc->regtype == regtype && rc->addr == addr) {
127                               rc->value = *valuep;
128                               return (1);         /* exists */
129                     }
130           }
131 
132           return (aml_simulate_regcontent_add(regtype, addr, *valuep));
133 }
134 
135 static u_int32_t
aml_simulate_prompt(char * msg,u_int32_t def_val)136 aml_simulate_prompt(char *msg, u_int32_t def_val)
137 {
138           char                buf[16], *ep;
139           u_int32_t val;
140 
141           val = def_val;
142           printf("DEBUG");
143           if (msg != NULL) {
144                     printf("%s", msg);
145           }
146           printf("(default: 0x%x / %u) >>", val, val);
147           fflush(stdout);
148 
149           bzero(buf, sizeof buf);
150           while (1) {
151                     if (read(0, buf, sizeof buf) == 0) {
152                               continue;
153                     }
154                     if (buf[0] == '\n') {
155                               break;    /* use default value */
156                     }
157                     if (buf[0] == '0' && buf[1] == 'x') {
158                               val = strtoq(buf, &ep, 16);
159                     } else {
160                               val = strtoq(buf, &ep, 10);
161                     }
162                     break;
163           }
164           return (val);
165 }
166 
167 static void
aml_simulation_regload(const char * dumpfile)168 aml_simulation_regload(const char *dumpfile)
169 {
170           char      buf[256], *np, *ep;
171           struct    ACPIRegionContent rc;
172           FILE      *fp;
173 
174           if (!aml_simulation_initialized) {
175                     return;
176           }
177           if ((fp = fopen(dumpfile, "r")) == NULL) {
178                     warn("%s", dumpfile);
179                     return;
180           }
181           while (fgets(buf, sizeof buf, fp) != NULL) {
182                     np = buf;
183                     /* reading region type */
184                     rc.regtype = strtoq(np, &ep, 10);
185                     if (np == ep) {
186                               continue;
187                     }
188                     np = ep;
189 
190                     /* reading address */
191                     rc.addr = strtoq(np, &ep, 16);
192                     if (np == ep) {
193                               continue;
194                     }
195                     np = ep;
196 
197                     /* reading value */
198                     rc.value = strtoq(np, &ep, 16);
199                     if (np == ep) {
200                               continue;
201                     }
202                     aml_simulate_regcontent_write(rc.regtype, rc.addr, &rc.value);
203           }
204 
205           fclose(fp);
206 }
207 
208 int
aml_region_read_simple(struct aml_region_handle * h,vm_offset_t offset,u_int32_t * valuep)209 aml_region_read_simple(struct aml_region_handle *h, vm_offset_t offset,
210     u_int32_t *valuep)
211 {
212           int                 state;
213           u_int8_t  val;
214           u_int32_t value, i;
215 
216           state = 0;
217           value = val = 0;
218           for (i = 0; i < h->unit; i++) {
219                     state = aml_simulate_regcontent_read(h->regtype,
220                         h->addr + offset + i, &val);
221                     if (state == -1) {
222                               goto out;
223                     }
224                     value |= val << (i * 8);
225           }
226           *valuep = value;
227 out:
228           return (state);
229 }
230 
231 int
aml_region_write_simple(struct aml_region_handle * h,vm_offset_t offset,u_int32_t value)232 aml_region_write_simple(struct aml_region_handle *h, vm_offset_t offset,
233     u_int32_t value)
234 {
235           int                 state;
236           u_int8_t  val;
237           u_int32_t i;
238 
239           state = 0;
240           val = 0;
241           for (i = 0; i < h->unit; i++) {
242                     val = value & 0xff;
243                     state = aml_simulate_regcontent_write(h->regtype,
244                         h->addr + offset + i, &val);
245                     if (state == -1) {
246                               goto out;
247                     }
248                     value = value >> 8;
249           }
250 out:
251           return (state);
252 }
253 
254 u_int32_t
aml_region_prompt_read(struct aml_region_handle * h,u_int32_t value)255 aml_region_prompt_read(struct aml_region_handle *h, u_int32_t value)
256 {
257           u_int32_t           retval;
258           char                buf[64];
259 
260           retval = value;
261           sprintf(buf, "[read(%d, 0x%lx)&mask:0x%x]",
262               h->regtype, h->addr, value);
263           if (aml_debug_prompt_reginput) {
264                     retval = aml_simulate_prompt(buf, value);
265           } else {
266                     printf("\t%s\n", buf);
267           }
268 
269           return (retval);
270 }
271 
272 u_int32_t
aml_region_prompt_write(struct aml_region_handle * h,u_int32_t value)273 aml_region_prompt_write(struct aml_region_handle *h, u_int32_t value)
274 {
275           u_int32_t           retval;
276           char                buf[64];
277 
278           retval = value;
279           if (aml_debug_prompt_regoutput) {
280                     printf("\n");
281                     sprintf(buf, "[write(%d, 0x%x, 0x%lx)]",
282                         h->regtype, value, h->addr);
283                     retval = aml_simulate_prompt(buf, value);
284           }
285 
286           return (retval);
287 }
288 
289 int
aml_region_prompt_update_value(u_int32_t orgval,u_int32_t value,struct aml_region_handle * h)290 aml_region_prompt_update_value(u_int32_t orgval, u_int32_t value,
291     struct aml_region_handle *h)
292 {
293           int       state;
294 
295           state = 0;
296           if (orgval != value) {
297                     state = aml_region_io(h->env, AML_REGION_OUTPUT, h->regtype,
298                         h->flags, &value, h->baseaddr, h->bitoffset, h->bitlen);
299                     if (state == -1) {
300                               goto out;
301                     }
302           }
303 
304 out:
305           return (state);
306 }
307 
308 static int
aml_simulate_region_io_buffer(int io,int regtype,u_int32_t flags,u_int8_t * buffer,u_int32_t baseaddr,u_int32_t bitoffset,u_int32_t bitlen)309 aml_simulate_region_io_buffer(int io, int regtype, u_int32_t flags,
310     u_int8_t *buffer, u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen)
311 {
312           u_int8_t  val;
313           u_int8_t  offsetlow, offsethigh;
314           u_int32_t addr, byteoffset, bytelen;
315           int                 state, i;
316 
317           val = 0;
318           offsetlow = offsethigh = 0;
319           state = 0;
320 
321           byteoffset = bitoffset / 8;
322           bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0);
323           addr = baseaddr + byteoffset;
324           offsetlow = bitoffset % 8;
325           assert(offsetlow == 0);
326 
327           if (bytelen > 1) {
328                     offsethigh = (bitlen - (8 - offsetlow)) % 8;
329           }
330           assert(offsethigh == 0);
331 
332           for (i = bytelen; i > 0; i--, addr++) {
333                     switch (io) {
334                     case AML_REGION_INPUT:
335                               val = 0;
336                               state = aml_simulate_regcontent_read(regtype, addr, &val);
337                               if (state == -1) {
338                                         goto finish;
339                               }
340                               buffer[bytelen - i] = val;
341                               break;
342                     case AML_REGION_OUTPUT:
343                               val = buffer[bytelen - i];
344                               state = aml_simulate_regcontent_write(regtype,
345                                   addr, &val);
346                               if (state == -1) {
347                                         goto finish;
348                               }
349                               break;
350                     }
351           }
352 finish:
353           return (state);
354 }
355 
356 static u_int32_t
aml_simulate_region_read(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)357 aml_simulate_region_read(struct aml_environ *env, int regtype,
358     u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen)
359 {
360           u_int32_t value;
361           int       state;
362 
363           state = aml_region_io(env, AML_REGION_INPUT, regtype, flags, &value,
364               addr, bitoffset, bitlen);
365           assert(state != -1);
366           return (value);
367 }
368 
369 static int
aml_simulate_region_read_into_buffer(int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int8_t * buffer)370 aml_simulate_region_read_into_buffer(int regtype, u_int32_t flags,
371     u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen, u_int8_t *buffer)
372 {
373           int       state;
374 
375           state = aml_simulate_region_io_buffer(AML_REGION_INPUT, regtype, flags,
376               buffer, addr, bitoffset, bitlen);
377           assert(state != -1);
378           return (state);
379 }
380 
381 static int
aml_simulate_region_write(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t value,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)382 aml_simulate_region_write(struct aml_environ *env, int regtype,
383     u_int32_t flags, u_int32_t value, u_int32_t addr, u_int32_t bitoffset,
384     u_int32_t bitlen)
385 {
386           int       state;
387 
388           state = aml_region_io(env, AML_REGION_OUTPUT, regtype, flags,
389               &value, addr, bitoffset, bitlen);
390           assert(state != -1);
391           return (state);
392 }
393 
394 static int
aml_simulate_region_write_from_buffer(int regtype,u_int32_t flags,u_int8_t * buffer,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)395 aml_simulate_region_write_from_buffer(int regtype, u_int32_t flags,
396     u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen)
397 {
398           int       state;
399 
400           state = aml_simulate_region_io_buffer(AML_REGION_OUTPUT, regtype,
401               flags, buffer, addr, bitoffset, bitlen);
402           assert(state != -1);
403           return (state);
404 }
405 
406 static int
aml_simulate_region_bcopy(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int32_t dflags,u_int32_t daddr,u_int32_t dbitoffset,u_int32_t dbitlen)407 aml_simulate_region_bcopy(struct aml_environ *env, int regtype,
408     u_int32_t flags, u_int32_t addr,
409     u_int32_t bitoffset, u_int32_t bitlen,
410     u_int32_t dflags, u_int32_t daddr,
411     u_int32_t dbitoffset, u_int32_t dbitlen)
412 {
413           u_int32_t len, i;
414           u_int32_t value;
415           int                 state;
416 
417           len = (bitlen > dbitlen) ? dbitlen : bitlen;
418           len = len / 8 + ((len % 8) ? 1 : 0);
419 
420           for (i = 0; i < len; i++) {
421                     state = aml_region_io(env, AML_REGION_INPUT, regtype,
422                         flags, &value, addr, bitoffset + i * 8, 8);
423                     assert(state != -1);
424                     state = aml_region_io(env, AML_REGION_OUTPUT, regtype,
425                         dflags, &value, daddr, dbitoffset + i * 8, 8);
426                     assert(state != -1);
427           }
428 
429           return (0);
430 }
431 
432 u_int32_t
aml_region_read(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)433 aml_region_read(struct aml_environ *env, int regtype, u_int32_t flags,
434     u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen)
435 {
436 
437           AML_REGION_READ_DEBUG(regtype, flags, addr, bitoffset, bitlen);
438 
439           return (aml_simulate_region_read(env, regtype, flags, addr,
440               bitoffset, bitlen));
441 }
442 
443 int
aml_region_read_into_buffer(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int8_t * buffer)444 aml_region_read_into_buffer(struct aml_environ *env, int regtype,
445     u_int32_t flags, u_int32_t addr, u_int32_t bitoffset,
446     u_int32_t bitlen, u_int8_t *buffer)
447 {
448 
449           AML_REGION_READ_INTO_BUFFER_DEBUG(regtype, flags, addr, bitoffset, bitlen);
450 
451           return (aml_simulate_region_read_into_buffer(regtype, flags, addr,
452               bitoffset, bitlen, buffer));
453 }
454 
455 int
aml_region_write(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t value,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)456 aml_region_write(struct aml_environ *env, int regtype, u_int32_t flags,
457     u_int32_t value, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen)
458 {
459 
460           AML_REGION_WRITE_DEBUG(regtype, flags, value, addr, bitoffset, bitlen);
461 
462           return (aml_simulate_region_write(env, regtype, flags, value, addr,
463               bitoffset, bitlen));
464 }
465 
466 int
aml_region_write_from_buffer(struct aml_environ * env,int regtype,u_int32_t flags,u_int8_t * buffer,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)467 aml_region_write_from_buffer(struct aml_environ *env, int regtype,
468     u_int32_t flags, u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset,
469     u_int32_t bitlen)
470 {
471 
472           AML_REGION_WRITE_FROM_BUFFER_DEBUG(regtype, flags,
473               addr, bitoffset, bitlen);
474 
475           return (aml_simulate_region_write_from_buffer(regtype, flags, buffer,
476               addr, bitoffset, bitlen));
477 }
478 
479 int
aml_region_bcopy(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int32_t dflags,u_int32_t daddr,u_int32_t dbitoffset,u_int32_t dbitlen)480 aml_region_bcopy(struct aml_environ *env, int regtype, u_int32_t flags,
481     u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen,
482     u_int32_t dflags, u_int32_t daddr,
483     u_int32_t dbitoffset, u_int32_t dbitlen)
484 {
485 
486           AML_REGION_BCOPY_DEBUG(regtype, flags, addr, bitoffset, bitlen,
487               dflags, daddr, dbitoffset, dbitlen);
488 
489           return (aml_simulate_region_bcopy(env, regtype, flags, addr, bitoffset,
490               bitlen, dflags, daddr, dbitoffset, dbitlen));
491 }
492 
493 void
aml_simulation_regdump(const char * dumpfile)494 aml_simulation_regdump(const char *dumpfile)
495 {
496           struct    ACPIRegionContent *rc;
497           FILE      *fp;
498 
499           if (!aml_simulation_initialized) {
500                     return;
501           }
502           if ((fp = fopen(dumpfile, "w")) == NULL) {
503                     warn("%s", dumpfile);
504                     return;
505           }
506           while (!TAILQ_EMPTY(&RegionContentList)) {
507                     rc = TAILQ_FIRST(&RegionContentList);
508                     fprintf(fp, "%d     0x%x      0x%x\n",
509                         rc->regtype, rc->addr, rc->value);
510                     TAILQ_REMOVE(&RegionContentList, rc, links);
511                     free(rc);
512           }
513 
514           fclose(fp);
515           TAILQ_INIT(&RegionContentList);
516 }
517