aboutsummaryrefslogtreecommitdiff
path: root/board/MAI/bios_emulator/scitech/src/v86bios/parser.y
blob: 21c4023dcdbb2d361ab63996dd9d692f572952a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
%{
#include <malloc.h>
#include <string.h>
#include "v86bios.h"
#include "pci.h"
    
#define YYSTYPE unsigned long
    
#define MAX_VAR 0x20

    CARD32 var[MAX_VAR];
    CARD32 var_mem;


i86biosRegs regs = { 00 };

enum mem_type { BYTE, WORD, LONG, STRING };
union mem_val {
   CARD32 integer;
   char *ptr;
} rec;

struct mem {
    enum mem_type type;
        union mem_val val;
    struct mem *next;
}; 

 
struct device Device = {FALSE,NONE,{0}};

extern void yyerror(char *s);
extern int yylex( void  );
 
static void boot(void);
static void dump_mem(CARD32 addr, int len);
static void exec_int(int num);
static void *add_to_list(enum mem_type type, union mem_val *rec, void *next);
static void do_list(struct mem *list, memType addr);
static char * normalize_string(char *ptr);
%}

%token TOK_NUM
%token TOK_REG_AX
%token TOK_REG_BX
%token TOK_REG_CX
%token TOK_REG_DX
%token TOK_REG_DI
%token TOK_REG_SI
%token TOK_SEG_DS
%token TOK_SEG_ES
%token TOK_SEP
%token TOK_VAR
%token TOK_VAR_MEM
%token TOK_COMMAND_BOOT
%token TOK_COMMAND_EXEC
%token TOK_SELECT
%token TOK_STRING
%token TOK_MODIFIER_BYTE
%token TOK_MODIFIER_WORD
%token TOK_MODIFIER_LONG
%token TOK_MODIFIER_MEMSET
%token TOK_COMMAND_MEMSET
%token TOK_COMMAND_MEMDUMP
%token TOK_COMMAND_QUIT
%token TOK_ERROR
%token TOK_END
%token TOK_ISA
%token TOK_PCI
%token TOK_BYTE
%token TOK_WORD
%token TOK_LONG
%token TOK_PRINT_PORT
%token TOK_IOSTAT
%token TOK_PRINT_IRQ
%token TOK_PPCI
%token TOK_PIP
%token TOK_TRACE
%token TOK_ON
%token TOK_OFF
%token TOK_VERBOSE
%token TOK_LOG
%token TOK_LOGOFF
%token TOK_CLSTAT
%token TOK_STDOUT
%token TOK_HLT
%token TOK_DEL
%token TOK_IOPERM
%token TOK_DUMP_PCI
%token TOK_BOOT_BIOS
%%
input:        | input line  
line:          end |  com_reg | com_var | com_select
              | com_boot | com_memset | com_memdump  | com_quit 
              | com_exec | hlp | config | verbose | logging | print | clstat 
              | com_hlt | ioperm | list_pci | boot_bios 
              | error end  { printf("unknown command\n"); }
;
end:           TOK_END
;
com_reg:        reg_off val end { *(CARD16*)$1 = $2 & 0xffff; }
              | reg_seg TOK_SEP reg_off val end {
                               *(CARD16*)$1 = ($4 & 0xf0000) >> 4;
                                       *(CARD16*)$3 = ($4 & 0x0ffff);
                                        }
              |  reg_off '?' end { printf("0x%x\n",*(CARD16*)$1);}
              |  reg_seg TOK_SEP reg_off '?' end
                                     { printf("0x%x:0x%x\n",*(CARD16*)$1,
                          *(CARD16*)$3); }
;
register_read:  reg_seg TOK_SEP reg_off { $$ = (((*(CARD16*)$1) << 4) 
                                                | ((*(CARD16*)$3) & 0xffff));
                                        }
              | reg_off          { $$ = ((*(CARD16*)$1) & 0xffff); }
;
reg_off:        TOK_REG_AX  { $$ = (unsigned long)&(regs.ax); }
              | TOK_REG_BX  { $$ = (unsigned long)&(regs.bx); }
              | TOK_REG_CX  { $$ = (unsigned long)&(regs.cx); }
              | TOK_REG_DX  { $$ = (unsigned long)&(regs.dx); }
              | TOK_REG_DI  { $$ = (unsigned long)&(regs.di); }
              | TOK_REG_SI  { $$ = (unsigned long)&(regs.si); }
;
reg_seg:        TOK_SEG_DS  { $$ = (unsigned long)&(regs.ds); }
              | TOK_SEG_ES  { $$ = (unsigned long)&(regs.es); }
;
com_var:        TOK_VAR_MEM '?' end { printf("var mem: 0x%x\n",var_mem); }
          | TOK_VAR '?' end { if ($1 < MAX_VAR)
          printf("var[%i]: 0x%x\n",(int)$1,var[$1]);
          else
          printf("var index %i out of range\n",(int)$1); }
          | TOK_VAR_MEM val end { var_mem = $2; }    
              | TOK_VAR val end    { if ($1 <= MAX_VAR)
                                 var[$1] = $2;
                              else 
                                     printf("var index %i out of range\n",(int)$1); }
              | TOK_VAR error  end { printf("$i val\n"); }
              | TOK_VAR_MEM error  end { printf("$i val\n"); }
;
com_boot:       TOK_COMMAND_BOOT  end { boot(); }
                TOK_COMMAND_BOOT error end { boot(); }
;
com_select:     TOK_SELECT TOK_ISA end { Device.booted = FALSE;
                                         Device.type = ISA;
                     CurrentPci = NULL; }   
              | TOK_SELECT TOK_PCI val TOK_SEP val TOK_SEP val end
                                    { Device.booted = FALSE;
                      Device.type = PCI; 
                                      Device.loc.pci.bus = $3;
                                      Device.loc.pci.dev = $5; 
                                      Device.loc.pci.func = $7; }
              | TOK_SELECT '?' end
                                   { switch (Device.type) {
                                     case ISA:
                                       printf("isa\n");
                                       break;
                                     case PCI:
                                      printf("pci: %x:%x:%x\n",Device.loc.pci.bus,
                                              Device.loc.pci.dev,
                          Device.loc.pci.func);
                                      break;
                                 default:
                                      printf("no device selected\n");
                                      break;
                                     }
                                    }
              | TOK_SELECT error end { printf("select ? | isa "
                                         "| pci:bus:dev:func\n"); }
;
com_quit:       TOK_COMMAND_QUIT end { return 0; }
              | TOK_COMMAND_QUIT error end { logoff(); return 0; }
;
com_exec:       TOK_COMMAND_EXEC end { exec_int(0x10); }
          | TOK_COMMAND_EXEC val end { exec_int($2); }
          | TOK_COMMAND_EXEC error end { exec_int(0x10); }
;
com_memdump:    TOK_COMMAND_MEMDUMP val val end { dump_mem($2,$3); }
              | TOK_COMMAND_MEMDUMP  error  end { printf("memdump start len\n"); }

    
;
com_memset:     TOK_COMMAND_MEMSET val list end { do_list((struct mem*)$3,$2);}
              | TOK_COMMAND_MEMSET error end { printf("setmem addr [byte val] "
                                                   "[word val] [long val] "
                                                   "[\"string\"]\n"); }
;
list:                              { $$ = 0; } 
              | TOK_BYTE val list { rec.integer = $2;
          $$ = (unsigned long)add_to_list(BYTE,&rec,(void*)$3); }
              | TOK_WORD val list { rec.integer = $2; 
          $$ = (unsigned long) add_to_list(WORD,&rec,(void*)$3); }
              | TOK_LONG val list { rec.integer = $2; 
          $$ = (unsigned long) add_to_list(LONG,&rec,(void*)$3); }
              | TOK_STRING list { rec.ptr = (void*)$1; 
          $$ = (unsigned long) add_to_list(STRING,&rec,(void*)$2); }
;
val:            TOK_VAR  {  if ($1 > MAX_VAR) {
                             printf("variable index out of range\n");
                             $$=0;
                             } else 
                            $$ = var[$1]; } 
              | TOK_NUM  {  $$ = $1; }
              | register_read
; 
bool:           TOK_ON   {  $$ = 1; }
              | TOK_OFF  {  $$ = 0; }
;
config:         TOK_PRINT_PORT bool end { Config.PrintPort = $2; } 
              | TOK_PRINT_PORT '?' end  { printf("print port %s\n",
                                      Config.PrintPort?"on":"off"); }
          | TOK_PRINT_PORT error end { printf("pport on | off | ?\n") } 
              | TOK_PRINT_IRQ bool end  { Config.PrintIrq = $2; } 
              | TOK_PRINT_IRQ '?' end   { printf("print irq %s\n",  
                                          Config.PrintIrq?"on":"off"); } 
          | TOK_PRINT_IRQ error end { printf("pirq on | off | ?\n") } 
              | TOK_PPCI bool end       { Config.PrintPci = $2; } 
              | TOK_PPCI '?' end        { printf("print PCI %s\n",
                                          Config.PrintPci?"on":"off"); } 
          | TOK_PPCI error end      { printf("ppci on | off | ?\n") } 
              | TOK_PIP bool end        { Config.PrintIp = $2; } 
              | TOK_PIP '?' end         { printf("printip %s\n",
                                      Config.PrintIp?"on":"off"); } 
          | TOK_PIP error end       { printf("pip on | off | ?\n") } 
              | TOK_IOSTAT bool end     { Config.IoStatistics = $2; } 
              | TOK_IOSTAT '?' end      { printf("io statistics %s\n",
                                      Config.IoStatistics?"on":"off"); } 
          | TOK_IOSTAT error end    { printf("iostat on | off | ?\n") } 
              | TOK_TRACE bool end      { Config.Trace = $2; } 
              | TOK_TRACE '?' end       { printf("trace %s\n",
                                      Config.Trace ?"on":"off"); } 
          | TOK_TRACE error end { printf("trace on | off | ?\n") } 
;
verbose:        TOK_VERBOSE val end     { Config.Verbose = $2; }
          | TOK_VERBOSE '?' end     { printf("verbose: %i\n",
                            Config.Verbose); }
          | TOK_VERBOSE error end   { printf("verbose val | ?\n"); }
;
logging:        TOK_LOG TOK_STRING end  { logon(normalize_string((char*)$2)); }
          | TOK_LOG '?' end         { if (logging) printf("logfile: %s\n",
                            logfile);
                      else printf("no logging\n?"); }
          | TOK_LOG TOK_OFF end          { logoff(); }
          | TOK_LOG error end       { printf("log \"<filename>\" | ? |"
                         " off\n"); }
;
clstat:         TOK_CLSTAT end          { clear_stat(); }
          | TOK_CLSTAT error end    { printf("clstat\n"); } 
;
print:          TOK_STDOUT bool end     { nostdout = !$2; }
                  | TOK_STDOUT '?' end      { printf("print %s\n",nostdout ?
                        "no":"yes"); }
          | TOK_STDOUT error end    { printf("print on | off\n"); }
;
com_hlt:            TOK_HLT val end         { add_hlt($2); }    
          | TOK_HLT TOK_DEL val end { del_hlt($3); }
          | TOK_HLT TOK_DEL end     { del_hlt(21); }
              | TOK_HLT '?' end         { list_hlt(); }
          | TOK_HLT error end       { printf(
                                               "hlt val | del [val] | ?\n"); }
;
ioperm:         TOK_IOPERM val val val end { int i,max;
                                             if ($2 >= 0) {
                                 max = $2 + $3 - 1;
                             if (max > IOPERM_BITS) 
                             max = IOPERM_BITS;
                                 for (i = $2;i <= max; i++)
                                ioperm_list[i] 
                                                                = $4>0 ? 1 : 0;
                          }
                                           }
          | TOK_IOPERM '?' end { int i,start;
                     for (i=0; i <= IOPERM_BITS; i++) {
                    if (ioperm_list[i]) {
                       start = i;
                       for (; i <= IOPERM_BITS; i++) 
                        if (!ioperm_list[i]) {
                         printf("ioperm on in "
                         "0x%x+0x%x\n", start,i-start);
                         break;
                        }
                         }
                     }
                                  }
          | TOK_IOPERM error end { printf("ioperm start len val\n"); }
;
list_pci:      TOK_DUMP_PCI end       { list_pci(); }
             | TOK_DUMP_PCI error end { list_pci(); }
;
boot_bios:     TOK_BOOT_BIOS '?' end { if (!BootBios) printf("No Boot BIOS\n");
                                   else printf("BootBIOS from: %i:%i:%i\n",
                           BootBios->bus, BootBios->dev,
                           BootBios->func); }
             | TOK_BOOT_BIOS error end { printf ("bootbios bus:dev:num\n"); }
;
hlp:         '?'  { printf("Command list:\n");
                    printf(" select isa | pci bus:dev:func\n");
            printf(" boot\n");
            printf(" seg:reg val | reg val \n");
            printf(" $x val | $mem val\n");
            printf(" setmem addr list; addr := val\n");
            printf(" dumpmem addr len; addr,len := val\n");
            printf(" do [val]\n");
            printf(" quit\n");
            printf(" ?\n");
            printf(" seg := ds | es;"
               " reg := ax | bx | cx | dx | si \n");
            printf(" val := var | <hex-number> | seg:reg | seg\n");
            printf(" var := $x | $mem; x := 0..20\n");
            printf(" list := byte val | word val | long val "
               "| \"string\"\n");
                printf(" pport on | off | ?\n");
                printf(" ppci on | off | ?\n");
                printf(" pirq on | off | ?\n");
                printf(" pip on | off | ?\n");
                printf(" trace on | off | ?\n");
                printf(" iostat on | off | ?\n");
            printf(" verbose val\n");
            printf(" log \"<filename>\" | off | ?\n");
            printf(" print on | off\n");
            printf(" hlt val | del [val] | ?\n");
            printf(" clstat\n");
            printf(" lpci\n");
            printf ("bootbios ?\n");
}
;

%%

static void
dump_mem(CARD32 addr, int len)
{
    dprint(addr,len);
}

static void
exec_int(int num)
{
    if (num == 0x10) {  /* video interrupt */
    if (Device.type == NONE) {
        CurrentPci = PciList;
        while (CurrentPci) {
        if (CurrentPci->active)
            break;
        CurrentPci = CurrentPci->next;
        }
        if (!CurrentPci)
        Device.type = ISA;
        else {
        Device.type = PCI;
        Device.loc.pci.dev = CurrentPci->dev;
        Device.loc.pci.bus = CurrentPci->bus;
        Device.loc.pci.func = CurrentPci->func;
        }
    }
        if (Device.type != ISA) {
       if (!Device.booted) {
              if (!CurrentPci || (Device.type == PCI
               && (!CurrentPci->active
                   && (Device.loc.pci.dev != CurrentPci->dev
                 || Device.loc.pci.bus != CurrentPci->bus
                 || Device.loc.pci.func != CurrentPci->func)))) {
                printf("boot the device fist\n");
            return;
          }
           }
    } else
       CurrentPci = NULL;
    } else {
    Device.booted = FALSE; /* we need this for sanity! */
    }
    
    runINT(num,&regs);
}

static void
boot(void)
{
    if (Device.type == NONE) {
    printf("select a device fist\n");
    return;
    }
    
    call_boot(&Device);
}

static void *
add_to_list(enum mem_type type, union mem_val *rec, void *next)
{
    struct mem *mem_rec = (struct mem *) malloc(sizeof(mem_rec));

    mem_rec->type = type;
    mem_rec->next = next;
    
    switch (type) {
    case BYTE:
    case WORD:
    case LONG:
    mem_rec->val.integer = rec->integer;
       break;
    case STRING:
    mem_rec->val.ptr = normalize_string(rec->ptr);
    break;
    }
    return mem_rec;
}

static int
validRange(int addr,int len)
{
    int end = addr + len;

    if (addr < 0x1000 || end > 0xc0000)
    return 0;
    return 1;
}

static void
do_list(struct mem *list, memType addr)
{
   struct mem *prev;
   int len;
   
   while (list) {
    switch (list->type) {
         case BYTE:
         if (!validRange(addr,1)) goto error;
         *(CARD8*)addr = list->val.integer;
         addr =+ 1;
             break;     
         case WORD:
         if (!validRange(addr,2)) goto error;
         *(CARD16*)addr = list->val.integer;
         addr =+ 2;
             break;     
         case LONG:
         if (!validRange(addr,4)) goto error;
         *(CARD32*)addr = list->val.integer;
         addr =+ 4;
             break;
         case STRING:
         len = strlen((char*)list->val.ptr);
         if (!validRange(addr,len)) goto error;
         memcpy((CARD8*)addr,(void*)list->val.ptr,len);
         addr =+ len;
             free(list->val.ptr);
             break;
       }     
       prev = list;
       list = list->next;
       free(prev);
       continue;
   error:
       printf("address out of range\n");
       while (list) {
       prev = list;
       list = list->next;
       free(prev);
       }
       break;
   }
}

static char *
normalize_string(char *ptr)
{
    int i = 0, j = 0, c = 0, esc= 0;
    int size;
    char *mem_ptr;
    
    size = strlen(ptr);
    mem_ptr = malloc(size);
    while (1) {
        switch (*(ptr + i)) {
        case '\\':
            if (esc) {
                *(mem_ptr + j++) = *(ptr + i);
                esc = 0;
            } else 
                esc = 1;
            break;
        case '\"':
            if (esc) {
                *(mem_ptr + j++) = *(ptr + i);
                esc = 0;
            } else 
                c++;
            break;
        default:
            *(mem_ptr + j++) = *(ptr + i);
            break;
        }
        if (c > 1) {
            *(mem_ptr + j) = '\0';     
            break;
        }
        i++;
    }
    return mem_ptr;
}