PCI enhancements.
[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 = 0x70008086,
54         .checksum = 0x07, // 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->bx = d.devfn;
156     set_code_success(regs);
157 }
158
159 // find class code
160 static void
161 handle_1ab103(struct bregs *regs)
162 {
163     PCIDevice d;
164     int ret = pci_find_class(regs->ecx, regs->si, &d);
165     if (ret) {
166         set_code_fail(regs, RET_DEVICE_NOT_FOUND);
167         return;
168     }
169     regs->bx = d.devfn;
170     set_code_success(regs);
171 }
172
173 // read configuration byte
174 static void
175 handle_1ab108(struct bregs *regs)
176 {
177     regs->cl = pci_config_readb(pci_bd(regs->bh, regs->bl), regs->di);
178     set_code_success(regs);
179 }
180
181 // read configuration word
182 static void
183 handle_1ab109(struct bregs *regs)
184 {
185     regs->cx = pci_config_readw(pci_bd(regs->bh, regs->bl), regs->di);
186     set_code_success(regs);
187 }
188
189 // read configuration dword
190 static void
191 handle_1ab10a(struct bregs *regs)
192 {
193     regs->ecx = pci_config_readl(pci_bd(regs->bh, regs->bl), regs->di);
194     set_code_success(regs);
195 }
196
197 // write configuration byte
198 static void
199 handle_1ab10b(struct bregs *regs)
200 {
201     pci_config_writeb(pci_bd(regs->bh, regs->bl), regs->di, regs->cl);
202     set_code_success(regs);
203 }
204
205 // write configuration word
206 static void
207 handle_1ab10c(struct bregs *regs)
208 {
209     pci_config_writew(pci_bd(regs->bh, regs->bl), regs->di, regs->cx);
210     set_code_success(regs);
211 }
212
213 // write configuration dword
214 static void
215 handle_1ab10d(struct bregs *regs)
216 {
217     pci_config_writel(pci_bd(regs->bh, regs->bl), regs->di, regs->ecx);
218     set_code_success(regs);
219 }
220
221 // get irq routing options
222 static void
223 handle_1ab10e(struct bregs *regs)
224 {
225     if (! CONFIG_PIRTABLE) {
226         set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
227         return;
228     }
229
230     // Validate and update size.
231     u16 size = GET_FARVAR(regs->es, *(u16*)(regs->di+0));
232     u32 pirsize = sizeof(PIR_TABLE.slots);
233     SET_FARVAR(regs->es, *(u16*)(regs->di+0), pirsize);
234     if (size < pirsize) {
235         set_code_fail(regs, RET_BUFFER_TOO_SMALL);
236         return;
237     }
238
239     // Get dest buffer.
240     u8 *d = (u8*)(GET_FARVAR(regs->es, *(u16*)(regs->di+2)) + 0);
241     u16 destseg = GET_FARVAR(regs->es, *(u16*)(regs->di+4));
242
243     // Memcpy pir table slots to dest buffer.
244     u8 *p = (u8*)PIR_TABLE.slots;
245     u8 *end = p + pirsize;
246     for (; p<end; p++, d++) {
247         u8 c = GET_VAR(CS, *p);
248         SET_FARVAR(destseg, *d, c);
249     }
250
251     // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
252     regs->bx = GET_VAR(CS, PIR_TABLE.pir.exclusive_irqs);
253     set_code_success(regs);
254 }
255
256 static void
257 handle_1ab1XX(struct bregs *regs)
258 {
259     set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
260 }
261
262 void
263 handle_1ab1(struct bregs *regs)
264 {
265     //debug_stub(regs);
266
267     if (! CONFIG_PCIBIOS) {
268         set_fail(regs);
269         return;
270     }
271
272     switch (regs->al) {
273     case 0x01: handle_1ab101(regs); break;
274     case 0x02: handle_1ab102(regs); break;
275     case 0x03: handle_1ab103(regs); break;
276     case 0x08: handle_1ab108(regs); break;
277     case 0x09: handle_1ab109(regs); break;
278     case 0x0a: handle_1ab10a(regs); break;
279     case 0x0b: handle_1ab10b(regs); break;
280     case 0x0c: handle_1ab10c(regs); break;
281     case 0x0d: handle_1ab10d(regs); break;
282     case 0x0e: handle_1ab10e(regs); break;
283     default:   handle_1ab1XX(regs); break;
284     }
285 }