SandboXP

Форк
0
/
apic.js 
630 строк · 16.4 Кб
1
"use strict";
2

3
// See Intel's System Programming Guide
4

5

6
/** @const */
7
var APIC_LOG_VERBOSE = false;
8

9
/** @const */
10
var APIC_ADDRESS = 0xFEE00000;
11

12
/** @const */
13
var APIC_TIMER_MODE_MASK = 3 << 17;
14

15
/** @const */
16
var APIC_TIMER_MODE_ONE_SHOT = 0;
17

18
/** @const */
19
var APIC_TIMER_MODE_PERIODIC = 1 << 17;
20

21
/** @const */
22
var APIC_TIMER_MODE_TSC = 2 << 17;
23

24

25
/** @const */
26
var DELIVERY_MODES = [
27
    "Fixed (0)",
28
    "Lowest Prio (1)",
29
    "SMI (2)",
30
    "Reserved (3)",
31
    "NMI (4)",
32
    "INIT (5)",
33
    "Reserved (6)",
34
    "ExtINT (7)",
35
];
36

37
/** @const */
38
var DESTINATION_MODES = ["physical", "logical"];
39

40

41
/**
42
 * @constructor
43
 * @param {CPU} cpu
44
 */
45
function APIC(cpu)
46
{
47
    /** @type {CPU} */
48
    this.cpu = cpu;
49

50
    this.apic_id = 0;
51

52
    this.timer_divider = 0;
53
    this.timer_divider_shift = 1;
54
    this.timer_initial_count = 0;
55
    this.timer_current_count = 0;
56

57
    this.next_tick = v86.microtick();
58

59
    this.lvt_timer = IOAPIC_CONFIG_MASKED;
60
    this.lvt_perf_counter = IOAPIC_CONFIG_MASKED;
61
    this.lvt_int0 = IOAPIC_CONFIG_MASKED;
62
    this.lvt_int1 = IOAPIC_CONFIG_MASKED;
63
    this.lvt_error = IOAPIC_CONFIG_MASKED;
64

65
    this.tpr = 0;
66
    this.icr0 = 0;
67
    this.icr1 = 0;
68

69
    this.irr = new Int32Array(8);
70
    this.isr = new Int32Array(8);
71
    this.tmr = new Int32Array(8);
72

73
    this.spurious_vector = 0xFE;
74
    this.destination_format = -1;
75
    this.local_destination = 0;
76

77
    this.error = 0;
78
    this.read_error = 0;
79

80
    cpu.io.mmap_register(APIC_ADDRESS, 0x100000,
81
        (addr) =>
82
        {
83
            dbg_log("Unsupported read8 from apic: " + h(addr >>> 0), LOG_APIC);
84
            var off = addr & 3;
85
            addr &= ~3;
86
            return this.read32(addr) >> (off * 8) & 0xFF;
87
        },
88
        (addr, value) =>
89
        {
90
            dbg_log("Unsupported write8 from apic: " + h(addr) + " <- " + h(value), LOG_APIC);
91
            dbg_trace();
92
            dbg_assert(false);
93
        },
94
        (addr) => this.read32(addr),
95
        (addr, value) => this.write32(addr, value)
96
    );
97
}
98

99
APIC.prototype.read32 = function(addr)
100
{
101
    addr = addr - APIC_ADDRESS | 0;
102

103
    switch(addr)
104
    {
105
        case 0x20:
106
            dbg_log("APIC read id", LOG_APIC);
107
            return this.apic_id;
108

109
        case 0x30:
110
            // version
111
            dbg_log("APIC read version", LOG_APIC);
112
            return 0x50014;
113

114
        case 0x80:
115
            APIC_LOG_VERBOSE && dbg_log("APIC read tpr", LOG_APIC);
116
            return this.tpr;
117

118
        case 0xD0:
119
            dbg_log("Read local destination", LOG_APIC);
120
            return this.local_destination;
121

122
        case 0xE0:
123
            dbg_log("Read destination format", LOG_APIC);
124
            return this.destination_format;
125

126
        case 0xF0:
127
            return this.spurious_vector;
128

129
        case 0x100:
130
        case 0x110:
131
        case 0x120:
132
        case 0x130:
133
        case 0x140:
134
        case 0x150:
135
        case 0x160:
136
        case 0x170:
137
            var index = addr - 0x100 >> 4;
138
            dbg_log("Read isr " + index + ": " + h(this.isr[index] >>> 0, 8), LOG_APIC);
139
            return this.isr[index];
140

141
        case 0x180:
142
        case 0x190:
143
        case 0x1A0:
144
        case 0x1B0:
145
        case 0x1C0:
146
        case 0x1D0:
147
        case 0x1E0:
148
        case 0x1F0:
149
            var index = addr - 0x180 >> 4;
150
            dbg_log("Read tmr " + index + ": " + h(this.tmr[index] >>> 0, 8), LOG_APIC);
151
            return this.tmr[index];
152

153
        case 0x200:
154
        case 0x210:
155
        case 0x220:
156
        case 0x230:
157
        case 0x240:
158
        case 0x250:
159
        case 0x260:
160
        case 0x270:
161
            var index = addr - 0x200 >> 4;
162
            dbg_log("Read irr " + index + ": " + h(this.irr[index] >>> 0, 8), LOG_APIC);
163
            return this.irr[index];
164

165
        case 0x280:
166
            dbg_log("Read error: " + h(this.read_error >>> 0, 8), LOG_APIC);
167
            return this.read_error;
168

169
        case 0x300:
170
            APIC_LOG_VERBOSE && dbg_log("APIC read icr0", LOG_APIC);
171
            return this.icr0;
172

173
        case 0x310:
174
            dbg_log("APIC read icr1", LOG_APIC);
175
            return this.icr1;
176

177
        case 0x320:
178
            dbg_log("read timer lvt", LOG_APIC);
179
            return this.lvt_timer;
180

181
        case 0x340:
182
            dbg_log("read lvt perf counter", LOG_APIC);
183
            return this.lvt_perf_counter;
184

185
        case 0x350:
186
            dbg_log("read lvt int0", LOG_APIC);
187
            return this.lvt_int0;
188

189
        case 0x360:
190
            dbg_log("read lvt int1", LOG_APIC);
191
            return this.lvt_int1;
192

193
        case 0x370:
194
            dbg_log("read lvt error", LOG_APIC);
195
            return this.lvt_error;
196

197
        case 0x3E0:
198
            // divider
199
            dbg_log("read timer divider", LOG_APIC);
200
            return this.timer_divider;
201

202
        case 0x380:
203
            dbg_log("read timer initial count", LOG_APIC);
204
            return this.timer_initial_count;
205

206
        case 0x390:
207
            dbg_log("read timer current count: " + h(this.timer_current_count >>> 0, 8), LOG_APIC);
208
            return this.timer_current_count;
209

210
        default:
211
            dbg_log("APIC read " + h(addr), LOG_APIC);
212
            dbg_assert(false);
213
            return 0;
214
    }
215
};
216

217
APIC.prototype.write32 = function(addr, value)
218
{
219
    addr = addr - APIC_ADDRESS | 0;
220

221
    switch(addr)
222
    {
223
        case 0x30:
224
            // version
225
            dbg_log("APIC write version: " + h(value >>> 0, 8) + ", ignored", LOG_APIC);
226
            break;
227

228
        case 0x80:
229
            APIC_LOG_VERBOSE && dbg_log("Set tpr: " + h(value & 0xFF, 2), LOG_APIC);
230
            this.tpr = value & 0xFF;
231
            this.check_vector();
232
            break;
233

234
        case 0xB0:
235
            var highest_isr = this.highest_isr();
236
            if(highest_isr !== -1)
237
            {
238
                APIC_LOG_VERBOSE && dbg_log("eoi: " + h(value >>> 0, 8) + " for vector " + h(highest_isr), LOG_APIC);
239
                this.register_clear_bit(this.isr, highest_isr);
240
                if(this.register_get_bit(this.tmr, highest_isr))
241
                {
242
                    // Send eoi to all IO APICs
243
                    this.cpu.devices.ioapic.remote_eoi(highest_isr);
244
                }
245
                this.check_vector();
246
            }
247
            else
248
            {
249
                dbg_log("Bad eoi: No isr set", LOG_APIC);
250
            }
251
            break;
252

253
        case 0xD0:
254
            dbg_log("Set local destination: " + h(value >>> 0, 8), LOG_APIC);
255
            this.local_destination = value & 0xFF000000;
256
            break;
257

258
        case 0xE0:
259
            dbg_log("Set destination format: " + h(value >>> 0, 8), LOG_APIC);
260
            this.destination_format = value | 0xFFFFFF;
261
            break;
262

263
        case 0xF0:
264
            dbg_log("Set spurious vector: " + h(value >>> 0, 8), LOG_APIC);
265
            this.spurious_vector = value;
266
            break;
267

268
        case 0x280:
269
            // updated readable error register with real error
270
            dbg_log("Write error: " + h(value >>> 0, 8), LOG_APIC);
271
            this.read_error = this.error;
272
            this.error = 0;
273
            break;
274

275
        case 0x300:
276
            var vector = value & 0xFF;
277
            var delivery_mode = value >> 8 & 7;
278
            var destination_mode = value >> 11 & 1;
279
            var is_level = value >> 15 & 1;
280
            var destination_shorthand = value >> 18 & 3;
281
            var destination = this.icr1 >>> 24;
282
            dbg_log("APIC write icr0: " + h(value, 8) + " vector=" + h(vector, 2) + " " +
283
                    "destination_mode=" + DESTINATION_MODES[destination_mode] + " delivery_mode=" + DELIVERY_MODES[delivery_mode] + " " +
284
                    "destination_shorthand=" + ["no", "self", "all with self", "all without self"][destination_shorthand], LOG_APIC);
285

286
            value &= ~(1 << 12);
287
            this.icr0 = value;
288

289
            if(destination_shorthand === 0)
290
            {
291
                // no shorthand
292
                this.route(vector, delivery_mode, is_level, destination, destination_mode);
293
            }
294
            else if(destination_shorthand === 1)
295
            {
296
                // self
297
                this.deliver(vector, IOAPIC_DELIVERY_FIXED, is_level);
298
            }
299
            else if(destination_shorthand === 2)
300
            {
301
                // all including self
302
                this.deliver(vector, delivery_mode, is_level);
303
            }
304
            else if(destination_shorthand === 3)
305
            {
306
                // all but self
307
            }
308
            else
309
            {
310
                dbg_assert(false);
311
            }
312
            break;
313

314
        case 0x310:
315
            dbg_log("APIC write icr1: " + h(value >>> 0, 8), LOG_APIC);
316
            this.icr1 = value;
317
            break;
318

319
        case 0x320:
320
            dbg_log("timer lvt: " + h(value >>> 0, 8), LOG_APIC);
321
            this.lvt_timer = value;
322
            break;
323

324
        case 0x340:
325
            dbg_log("lvt perf counter: " + h(value >>> 0, 8), LOG_APIC);
326
            this.lvt_perf_counter = value;
327
            break;
328

329
        case 0x350:
330
            dbg_log("lvt int0: " + h(value >>> 0, 8), LOG_APIC);
331
            this.lvt_int0 = value;
332
            break;
333

334
        case 0x360:
335
            dbg_log("lvt int1: " + h(value >>> 0, 8), LOG_APIC);
336
            this.lvt_int1 = value;
337
            break;
338

339
        case 0x370:
340
            dbg_log("lvt error: " + h(value >>> 0, 8), LOG_APIC);
341
            this.lvt_error = value;
342
            break;
343

344
        case 0x3E0:
345
            dbg_log("timer divider: " + h(value >>> 0, 8), LOG_APIC);
346
            this.timer_divider = value;
347

348
            var divide_shift = value & 0b11 | (value & 0b1000) >> 1;
349
            this.timer_divider_shift = divide_shift === 0b111 ? 0 : divide_shift + 1;
350
            break;
351

352
        case 0x380:
353
            dbg_log("timer initial: " + h(value >>> 0, 8), LOG_APIC);
354
            this.timer_initial_count = value >>> 0;
355
            this.timer_current_count = value >>> 0;
356

357
            this.next_tick = v86.microtick();
358
            this.timer_active = true;
359
            break;
360

361
        case 0x390:
362
            dbg_log("timer current: " + h(value >>> 0, 8), LOG_APIC);
363
            dbg_assert(false, "read-only register");
364
            break;
365

366
        default:
367
            dbg_log("APIC write32 " + h(addr) + " <- " + h(value >>> 0, 8), LOG_APIC);
368
            dbg_assert(false);
369
    }
370
};
371

372
APIC.prototype.timer = function(now)
373
{
374
    if(this.timer_current_count === 0)
375
    {
376
        return 100;
377
    }
378

379
    const freq = APIC_TIMER_FREQ / (1 << this.timer_divider_shift);
380

381
    const steps = (now - this.next_tick) * freq >>> 0;
382

383
    this.next_tick += steps / freq;
384
    this.timer_current_count -= steps;
385

386
    if(this.timer_current_count <= 0)
387
    {
388
        var mode = this.lvt_timer & APIC_TIMER_MODE_MASK;
389

390
        if(mode === APIC_TIMER_MODE_PERIODIC)
391
        {
392
            this.timer_current_count = this.timer_current_count % this.timer_initial_count;
393

394
            if(this.timer_current_count <= 0)
395
            {
396
                this.timer_current_count += this.timer_initial_count;
397
            }
398
            dbg_assert(this.timer_current_count !== 0);
399

400
            if((this.lvt_timer & IOAPIC_CONFIG_MASKED) === 0)
401
            {
402
                this.deliver(this.lvt_timer & 0xFF, IOAPIC_DELIVERY_FIXED, false);
403
            }
404
        }
405
        else if(mode === APIC_TIMER_MODE_ONE_SHOT)
406
        {
407
            this.timer_current_count = 0;
408
            dbg_log("APIC timer one shot end", LOG_APIC);
409

410
            if((this.lvt_timer & IOAPIC_CONFIG_MASKED) === 0)
411
            {
412
                this.deliver(this.lvt_timer & 0xFF, IOAPIC_DELIVERY_FIXED, false);
413
            }
414
        }
415
    }
416

417
    return Math.max(0, this.timer_current_count / freq);
418
};
419

420
APIC.prototype.route = function(vector, mode, is_level, destination, destination_mode)
421
{
422
    // TODO
423
    this.deliver(vector, mode, is_level);
424
};
425

426
APIC.prototype.deliver = function(vector, mode, is_level)
427
{
428
    APIC_LOG_VERBOSE && dbg_log("Deliver " + h(vector, 2) + " mode=" + mode + " level=" + is_level, LOG_APIC);
429

430
    if(mode === IOAPIC_DELIVERY_INIT)
431
    {
432
        // TODO
433
        return;
434
    }
435

436
    if(mode === IOAPIC_DELIVERY_NMI)
437
    {
438
        // TODO
439
        return;
440
    }
441

442
    if(vector < 0x10 || vector === 0xFF)
443
    {
444
        dbg_assert(false, "TODO: Invalid vector");
445
    }
446

447
    if(this.register_get_bit(this.irr, vector))
448
    {
449
        dbg_log("Not delivered: irr already set, vector=" + h(vector, 2), LOG_APIC);
450
        return;
451
    }
452

453
    this.register_set_bit(this.irr, vector);
454

455
    if(is_level)
456
    {
457
        this.register_set_bit(this.tmr, vector);
458
    }
459
    else
460
    {
461
        this.register_clear_bit(this.tmr, vector);
462
    }
463

464
    this.check_vector();
465
};
466

467
APIC.prototype.highest_irr = function()
468
{
469
    var highest = this.register_get_highest_bit(this.irr);
470
    dbg_assert(highest !== 0xFF);
471
    dbg_assert(highest >= 0x10 || highest === -1);
472
    return highest;
473
};
474

475
APIC.prototype.highest_isr = function()
476
{
477
    var highest = this.register_get_highest_bit(this.isr);
478
    dbg_assert(highest !== 0xFF);
479
    dbg_assert(highest >= 0x10 || highest === -1);
480
    return highest;
481
};
482

483
APIC.prototype.check_vector = function()
484
{
485
    var highest_irr = this.highest_irr();
486

487
    if(highest_irr === -1)
488
    {
489
        return;
490
    }
491

492
    var highest_isr = this.highest_isr();
493

494
    if(highest_isr >= highest_irr)
495
    {
496
        APIC_LOG_VERBOSE && dbg_log("Higher isr, isr=" + h(highest_isr) + " irr=" + h(highest_irr), LOG_APIC);
497
        return;
498
    }
499

500
    if((highest_irr & 0xF0) <= (this.tpr & 0xF0))
501
    {
502
        APIC_LOG_VERBOSE && dbg_log("Higher tpr, tpr=" + h(this.tpr & 0xF0) + " irr=" + h(highest_irr), LOG_APIC);
503
        return;
504
    }
505

506
    this.cpu.handle_irqs();
507
};
508

509
APIC.prototype.acknowledge_irq = function()
510
{
511
    var highest_irr = this.highest_irr();
512

513
    if(highest_irr === -1)
514
    {
515
        //dbg_log("Spurious", LOG_APIC);
516
        return;
517
    }
518

519
    var highest_isr = this.highest_isr();
520

521
    if(highest_isr >= highest_irr)
522
    {
523
        APIC_LOG_VERBOSE && dbg_log("Higher isr, isr=" + h(highest_isr) + " irr=" + h(highest_irr), LOG_APIC);
524
        return;
525
    }
526

527
    if((highest_irr & 0xF0) <= (this.tpr & 0xF0))
528
    {
529
        APIC_LOG_VERBOSE && dbg_log("Higher tpr, tpr=" + h(this.tpr & 0xF0) + " irr=" + h(highest_irr), LOG_APIC);
530
        return;
531
    }
532

533
    this.register_clear_bit(this.irr, highest_irr);
534
    this.register_set_bit(this.isr, highest_irr);
535

536
    APIC_LOG_VERBOSE && dbg_log("Calling vector " + h(highest_irr), LOG_APIC);
537
    this.cpu.pic_call_irq(highest_irr);
538

539
    this.check_vector();
540
};
541

542
APIC.prototype.get_state = function()
543
{
544
    var state = [];
545

546
    state[0] = this.apic_id;
547
    state[1] = this.timer_divider;
548
    state[2] = this.timer_divider_shift;
549
    state[3] = this.timer_initial_count;
550
    state[4] = this.timer_current_count;
551
    state[5] = this.next_tick;
552
    state[6] = this.lvt_timer;
553
    state[7] = this.lvt_perf_counter;
554
    state[8] = this.lvt_int0;
555
    state[9] = this.lvt_int1;
556
    state[10] = this.lvt_error;
557
    state[11] = this.tpr;
558
    state[12] = this.icr0;
559
    state[13] = this.icr1;
560
    state[14] = this.irr;
561
    state[15] = this.isr;
562
    state[16] = this.tmr;
563
    state[17] = this.spurious_vector;
564
    state[18] = this.destination_format;
565
    state[19] = this.local_destination;
566
    state[20] = this.error;
567
    state[21] = this.read_error;
568

569
    return state;
570
};
571

572
APIC.prototype.set_state = function(state)
573
{
574
    this.apic_id = state[0];
575
    this.timer_divider = state[1];
576
    this.timer_divider_shift = state[2];
577
    this.timer_initial_count = state[3];
578
    this.timer_current_count = state[4];
579
    this.next_tick = state[5];
580
    this.lvt_timer = state[6];
581
    this.lvt_perf_counter = state[7];
582
    this.lvt_int0 = state[8];
583
    this.lvt_int1 = state[9];
584
    this.lvt_error = state[10];
585
    this.tpr = state[11];
586
    this.icr0 = state[12];
587
    this.icr1 = state[13];
588
    this.irr = state[14];
589
    this.isr = state[15];
590
    this.tmr = state[16];
591
    this.spurious_vector = state[17];
592
    this.destination_format = state[18];
593
    this.local_destination = state[19];
594
    this.error = state[20];
595
    this.read_error = state[21];
596
};
597

598
// functions operating on 256-bit registers (for irr, isr, tmr)
599
APIC.prototype.register_get_bit = function(v, bit)
600
{
601
    dbg_assert(bit >= 0 && bit < 256);
602
    return v[bit >> 5] >> (bit & 31) & 1;
603
};
604

605
APIC.prototype.register_set_bit = function(v, bit)
606
{
607
    dbg_assert(bit >= 0 && bit < 256);
608
    v[bit >> 5] |= 1 << (bit & 31);
609
};
610

611
APIC.prototype.register_clear_bit = function(v, bit)
612
{
613
    dbg_assert(bit >= 0 && bit < 256);
614
    v[bit >> 5] &= ~(1 << (bit & 31));
615
};
616

617
APIC.prototype.register_get_highest_bit = function(v)
618
{
619
    for(var i = 7; i >= 0; i--)
620
    {
621
        var word = v[i];
622

623
        if(word)
624
        {
625
            return v86util.int_log2(word >>> 0) | i << 5;
626
        }
627
    }
628

629
    return -1;
630
};
631

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.