93cdc46238e98de5fc316776752fc853d132a7d9
[seabios.git] / src / pcibios.c
1 // PCI BIOS (int 1a/b1) calls
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU GPLv3 license.
7
8 #include "types.h" // u32
9 #include "util.h" // handle_1ab1
10 #include "pci.h" // pci_config_readl
11 #include "bregs.h" // struct bregs
12 #include "biosvar.h" // GET_EBDA
13
14 #define RET_FUNC_NOT_SUPPORTED 0x81
15 #define RET_BAD_VENDOR_ID      0x83
16 #define RET_DEVICE_NOT_FOUND   0x86
17 #define RET_BUFFER_TOO_SMALL   0x89
18
19 // installation check
20 static void
21 handle_1ab101(struct bregs *regs)
22 {
23     // Find max bus.
24     int bdf, max;
25     foreachpci(bdf, max, 0) {
26     }
27
28     regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
29     regs->bx = 0x0210; // PCI version 2.10
30     regs->cl = pci_bdf_to_bus(max - 1);
31     regs->edx = 0x20494350; // "PCI "
32     // XXX - bochs bios code sets edi to point to 32bit code - but no
33     // reference to this in spec.
34     set_code_success(regs);
35 }
36
37 // find pci device
38 static void
39 handle_1ab102(struct bregs *regs)
40 {
41     int bdf = -1;
42     int count = regs->si;
43     do {
44         bdf = pci_find_device(regs->dx, regs->cx, bdf+1);
45         if (bdf < 0) {
46             set_code_fail(regs, RET_DEVICE_NOT_FOUND);
47             return;
48         }
49     } while (count--);
50
51     regs->bx = bdf;
52     set_code_success(regs);
53 }
54
55 // find class code
56 static void
57 handle_1ab103(struct bregs *regs)
58 {
59     int bdf = -1;
60     int count = regs->si;
61     do {
62         bdf = pci_find_classprog(regs->ecx, bdf+1);
63         if (bdf < 0) {
64             set_code_fail(regs, RET_DEVICE_NOT_FOUND);
65             return;
66         }
67     } while (count--);
68
69     regs->bx = bdf;
70     set_code_success(regs);
71 }
72
73 // read configuration byte
74 static void
75 handle_1ab108(struct bregs *regs)
76 {
77     regs->cl = pci_config_readb(regs->bx, regs->di);
78     set_code_success(regs);
79 }
80
81 // read configuration word
82 static void
83 handle_1ab109(struct bregs *regs)
84 {
85     regs->cx = pci_config_readw(regs->bx, regs->di);
86     set_code_success(regs);
87 }
88
89 // read configuration dword
90 static void
91 handle_1ab10a(struct bregs *regs)
92 {
93     regs->ecx = pci_config_readl(regs->bx, regs->di);
94     set_code_success(regs);
95 }
96
97 // write configuration byte
98 static void
99 handle_1ab10b(struct bregs *regs)
100 {
101     pci_config_writeb(regs->bx, regs->di, regs->cl);
102     set_code_success(regs);
103 }
104
105 // write configuration word
106 static void
107 handle_1ab10c(struct bregs *regs)
108 {
109     pci_config_writew(regs->bx, regs->di, regs->cx);
110     set_code_success(regs);
111 }
112
113 // write configuration dword
114 static void
115 handle_1ab10d(struct bregs *regs)
116 {
117     pci_config_writel(regs->bx, regs->di, regs->ecx);
118     set_code_success(regs);
119 }
120
121 // get irq routing options
122 static void
123 handle_1ab10e(struct bregs *regs)
124 {
125     struct pir_header *pirtable_far = GET_EBDA(pir_loc);
126     if (! pirtable_far) {
127         set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
128         return;
129     }
130
131     // Validate and update size.
132     u16 size = GET_FARVAR(regs->es, *(u16*)(regs->di+0));
133     u16 pirsize = (GET_FARPTR(pirtable_far->size)
134                    - sizeof(struct pir_header));
135     SET_FARVAR(regs->es, *(u16*)(regs->di+0), pirsize);
136     if (size < pirsize) {
137         set_code_fail(regs, RET_BUFFER_TOO_SMALL);
138         return;
139     }
140
141     // Get dest buffer.
142     u16 d = (GET_FARVAR(regs->es, *(u16*)(regs->di+2)) + 0);
143     u16 destseg = GET_FARVAR(regs->es, *(u16*)(regs->di+4));
144
145     // Memcpy pir table slots to dest buffer.
146     memcpy_far(MAKE_FARPTR(destseg, d), pirtable_far, pirsize);
147
148     // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
149     regs->bx = GET_FARPTR(pirtable_far->exclusive_irqs);
150     set_code_success(regs);
151 }
152
153 static void
154 handle_1ab1XX(struct bregs *regs)
155 {
156     set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
157 }
158
159 void
160 handle_1ab1(struct bregs *regs)
161 {
162     //debug_stub(regs);
163
164     if (! CONFIG_PCIBIOS) {
165         set_fail(regs);
166         return;
167     }
168
169     switch (regs->al) {
170     case 0x01: handle_1ab101(regs); break;
171     case 0x02: handle_1ab102(regs); break;
172     case 0x03: handle_1ab103(regs); break;
173     case 0x08: handle_1ab108(regs); break;
174     case 0x09: handle_1ab109(regs); break;
175     case 0x0a: handle_1ab10a(regs); break;
176     case 0x0b: handle_1ab10b(regs); break;
177     case 0x0c: handle_1ab10c(regs); break;
178     case 0x0d: handle_1ab10d(regs); break;
179     case 0x0e: handle_1ab10e(regs); break;
180     default:   handle_1ab1XX(regs); break;
181     }
182 }