:: limine / common / sys / a20.s2.c 1.8 KB raw

1
#if defined (BIOS)
2
3
#include <stdint.h>
4
#include <stddef.h>
5
#include <stdbool.h>
6
#include <sys/a20.h>
7
#include <sys/cpu.h>
8
#include <lib/real.h>
9
10
#define A20_KBC_TIMEOUT 50000
11
12
static bool a20_kbc_wait(uint8_t mask, uint8_t expected) {
13
    for (int i = 0; i < A20_KBC_TIMEOUT; i++) {
14
        if ((inb(0x64) & mask) == expected)
15
            return true;
16
    }
17
    return false;
18
}
19
20
bool a20_check(void) {
21
    bool ret = false;
22
    uint16_t orig = mminw(0x7dfe);
23
24
    mmoutw(0x7dfe, 0x1234);
25
26
    if (mminw(0x7dfe) != mminw(0x7dfe + 0x100000)) {
27
        ret = true;
28
        goto out;
29
    }
30
31
    mmoutw(0x7dfe, ~mminw(0x7dfe));
32
33
    if (mminw(0x7dfe) != mminw(0x7dfe + 0x100000)) {
34
        ret = true;
35
        goto out;
36
    }
37
38
out:
39
    mmoutw(0x7dfe, orig);
40
    return ret;
41
}
42
43
// Keyboard controller method code below taken from:
44
// https://wiki.osdev.org/A20_Line
45
46
bool a20_enable(void) {
47
    if (a20_check())
48
        return true;
49
50
    // BIOS method
51
    struct rm_regs r = {0};
52
    r.eax = 0x2401;
53
    rm_int(0x15, &r, &r);
54
55
    if (a20_check())
56
        return true;
57
58
    // Keyboard controller method (with timeout for systems without KBC)
59
    if (!a20_kbc_wait(2, 0)) goto kbc_failed;
60
    outb(0x64, 0xad);
61
    if (!a20_kbc_wait(2, 0)) goto kbc_failed;
62
    outb(0x64, 0xd0);
63
    if (!a20_kbc_wait(1, 1)) goto kbc_failed;
64
    uint8_t b = inb(0x60);
65
    if (!a20_kbc_wait(2, 0)) goto kbc_failed;
66
    outb(0x64, 0xd1);
67
    if (!a20_kbc_wait(2, 0)) goto kbc_failed;
68
    outb(0x60, b | 2);
69
    if (!a20_kbc_wait(2, 0)) goto kbc_failed;
70
    outb(0x64, 0xae);
71
    if (!a20_kbc_wait(2, 0)) goto kbc_failed;
72
73
    if (a20_check())
74
        return true;
75
76
kbc_failed:
77
78
    // Fast A20 method
79
    b = inb(0x92);
80
    if ((b & 0x02) == 0) {
81
        b &= ~0x01;
82
        b |= 0x02;
83
        outb(0x92, b);
84
    }
85
86
    if (a20_check())
87
        return true;
88
89
    return false;
90
}
91
92
#endif
tab: 248 wrap: offon