Update PCI devid of PIR table.
[seabios.git] / src / pcibios.c
1 // Low level ATA disk access
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
12
13 /****************************************************************
14  * PIR table
15  ****************************************************************/
16
17 struct pir {
18     u32 signature;
19     u16 version;
20     u16 size;
21     u8 router_bus;
22     u8 router_devfunc;
23     u16 exclusive_irqs;
24     u32 compatible_devid;
25     u32 miniport_data;
26     u8 reserved[11];
27     u8 checksum;
28 } PACKED;
29
30 struct link_info {
31     u8 link;
32     u16 bitmap;
33 } PACKED;
34
35 struct pir_slot {
36     u8 bus;
37     u8 dev;
38     struct link_info links[4];
39     u8 slot_nr;
40     u8 reserved;
41 } PACKED;
42
43 struct pir_table {
44     struct pir pir;
45     struct pir_slot slots[6];
46 } PACKED PIR_TABLE VISIBLE16 __attribute__((aligned(16))) = {
47 #if CONFIG_PIRTABLE
48     .pir = {
49         .signature = 0x52495024, // "$PIR"
50         .version = 0x0100,
51         .size = sizeof(struct pir_table),
52         .router_devfunc = 0x08,
53         .compatible_devid = 0x122e8086,
54         .checksum = 0x37, // XXX - should auto calculate
55     },
56     .slots = {
57         {
58             // first slot entry PCI-to-ISA (embedded)
59             .dev = 1<<3,
60             .links = {
61                 {.link = 0x60, .bitmap = 0xdef8}, // INTA#
62                 {.link = 0x61, .bitmap = 0xdef8}, // INTB#
63                 {.link = 0x62, .bitmap = 0xdef8}, // INTC#
64                 {.link = 0x63, .bitmap = 0xdef8}, // INTD#
65             },
66             .slot_nr = 0, // embedded
67         }, {
68             // second slot entry: 1st PCI slot
69             .dev = 2<<3,
70             .links = {
71                 {.link = 0x61, .bitmap = 0xdef8}, // INTA#
72                 {.link = 0x62, .bitmap = 0xdef8}, // INTB#
73                 {.link = 0x63, .bitmap = 0xdef8}, // INTC#
74                 {.link = 0x60, .bitmap = 0xdef8}, // INTD#
75             },
76             .slot_nr = 1,
77         }, {
78             // third slot entry: 2nd PCI slot
79             .dev = 3<<3,
80             .links = {
81                 {.link = 0x62, .bitmap = 0xdef8}, // INTA#
82                 {.link = 0x63, .bitmap = 0xdef8}, // INTB#
83                 {.link = 0x60, .bitmap = 0xdef8}, // INTC#
84                 {.link = 0x61, .bitmap = 0xdef8}, // INTD#
85             },
86             .slot_nr = 2,
87         }, {
88             // 4th slot entry: 3rd PCI slot
89             .dev = 4<<3,
90             .links = {
91                 {.link = 0x63, .bitmap = 0xdef8}, // INTA#
92                 {.link = 0x60, .bitmap = 0xdef8}, // INTB#
93                 {.link = 0x61, .bitmap = 0xdef8}, // INTC#
94                 {.link = 0x62, .bitmap = 0xdef8}, // INTD#
95             },
96             .slot_nr = 3,
97         }, {
98             // 5th slot entry: 4rd PCI slot
99             .dev = 5<<3,
100             .links = {
101                 {.link = 0x60, .bitmap = 0xdef8}, // INTA#
102                 {.link = 0x61, .bitmap = 0xdef8}, // INTB#
103                 {.link = 0x62, .bitmap = 0xdef8}, // INTC#
104                 {.link = 0x63, .bitmap = 0xdef8}, // INTD#
105             },
106             .slot_nr = 4,
107         }, {
108             // 6th slot entry: 5rd PCI slot
109             .dev = 6<<3,
110             .links = {
111                 {.link = 0x61, .bitmap = 0xdef8}, // INTA#
112                 {.link = 0x62, .bitmap = 0xdef8}, // INTB#
113                 {.link = 0x63, .bitmap = 0xdef8}, // INTC#
114                 {.link = 0x60, .bitmap = 0xdef8}, // INTD#
115             },
116             .slot_nr = 5,
117         },
118     }
119 #endif // CONFIG_PIRTABLE
120 };
121
122
123 /****************************************************************
124  * Helper functions
125  ****************************************************************/
126
127 #define RET_FUNC_NOT_SUPPORTED 0x81
128 #define RET_BAD_VENDOR_ID      0x83
129 #define RET_DEVICE_NOT_FOUND   0x86
130 #define RET_BUFFER_TOO_SMALL   0x89
131
132 // installation check
133 static void
134 handle_1ab101(struct bregs *regs)
135 {
136     regs->ax = 0x0001;
137     regs->bx = 0x0210;
138     regs->cx = 0;
139     regs->edx = 0x20494350; // "PCI "
140     // XXX - bochs bios code sets edi to point to 32bit code - but no
141     // reference to this in spec.
142     set_success(regs);
143 }
144
145 // find pci device
146 static void
147 handle_1ab102(struct bregs *regs)
148 {
149     PCIDevice d;
150     int ret = pci_find_device(regs->cx, regs->dx, regs->si, &d);
151     if (ret) {
152         set_code_fail(regs, RET_DEVICE_NOT_FOUND);
153         return;
154     }
155     regs->bh = d.bus;
156     regs->bl = d.devfn;
157     set_code_success(regs);
158 }
159
160 // find class code
161 static void
162 handle_1ab103(struct bregs *regs)
163 {
164     PCIDevice d;
165     int ret = pci_find_class(regs->ecx, regs->si, &d);
166     if (ret) {
167         set_code_fail(regs, RET_DEVICE_NOT_FOUND);
168         return;
169     }
170     regs->bh = d.bus;
171     regs->bl = d.devfn;
172     set_code_success(regs);
173 }
174
175 // read configuration byte
176 static void
177 handle_1ab108(struct bregs *regs)
178 {
179     regs->cl = pci_config_readb(pci_bd(regs->bh, regs->bl), regs->di);
180     set_code_success(regs);
181 }
182
183 // read configuration word
184 static void
185 handle_1ab109(struct bregs *regs)
186 {
187     regs->cx = pci_config_readw(pci_bd(regs->bh, regs->bl), regs->di);
188     set_code_success(regs);
189 }
190
191 // read configuration dword
192 static void
193 handle_1ab10a(struct bregs *regs)
194 {
195     regs->ecx = pci_config_readl(pci_bd(regs->bh, regs->bl), regs->di);
196     set_code_success(regs);
197 }
198
199 // write configuration byte
200 static void
201 handle_1ab10b(struct bregs *regs)
202 {
203     pci_config_writeb(pci_bd(regs->bh, regs->bl), regs->di, regs->cl);
204     set_code_success(regs);
205 }
206
207 // write configuration word
208 static void
209 handle_1ab10c(struct bregs *regs)
210 {
211     pci_config_writew(pci_bd(regs->bh, regs->bl), regs->di, regs->cx);
212     set_code_success(regs);
213 }
214
215 // write configuration dword
216 static void
217 handle_1ab10d(struct bregs *regs)
218 {
219     pci_config_writel(pci_bd(regs->bh, regs->bl), regs->di, regs->ecx);
220     set_code_success(regs);
221 }
222
223 // get irq routing options
224 static void
225 handle_1ab10e(struct bregs *regs)
226 {
227     if (! CONFIG_PIRTABLE) {
228         set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
229         return;
230     }
231
232     // Validate and update size.
233     u16 size = GET_FARVAR(regs->es, *(u16*)(regs->di+0));
234     u32 pirsize = sizeof(PIR_TABLE.slots);
235     SET_FARVAR(regs->es, *(u16*)(regs->di+0), pirsize);
236     if (size < pirsize) {
237         set_code_fail(regs, RET_BUFFER_TOO_SMALL);
238         return;
239     }
240
241     // Get dest buffer.
242     u8 *d = (u8*)(GET_FARVAR(regs->es, *(u16*)(regs->di+2)) + 0);
243     u16 destseg = GET_FARVAR(regs->es, *(u16*)(regs->di+4));
244
245     // Memcpy pir table slots to dest buffer.
246     u8 *p = (u8*)PIR_TABLE.slots;
247     u8 *end = p + pirsize;
248     for (; p<end; p++, d++) {
249         u8 c = GET_VAR(CS, *p);
250         SET_FARVAR(destseg, *d, c);
251     }
252
253     // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
254     regs->bx = GET_VAR(CS, PIR_TABLE.pir.exclusive_irqs);
255     set_code_success(regs);
256 }
257
258 static void
259 handle_1ab1XX(struct bregs *regs)
260 {
261     set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
262 }
263
264 void
265 handle_1ab1(struct bregs *regs)
266 {
267     //debug_stub(regs);
268
269     if (! CONFIG_PCIBIOS) {
270         set_fail(regs);
271         return;
272     }
273
274     switch (regs->al) {
275     case 0x01: handle_1ab101(regs); break;
276     case 0x02: handle_1ab102(regs); break;
277     case 0x03: handle_1ab103(regs); break;
278     case 0x08: handle_1ab108(regs); break;
279     case 0x09: handle_1ab109(regs); break;
280     case 0x0a: handle_1ab10a(regs); break;
281     case 0x0b: handle_1ab10b(regs); break;
282     case 0x0c: handle_1ab10c(regs); break;
283     case 0x0d: handle_1ab10d(regs); break;
284     case 0x0e: handle_1ab10e(regs); break;
285     default:   handle_1ab1XX(regs); break;
286     }
287 }