Add support for 32bit PCI BIOS entry.
[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 LGPLv3 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 #include "pci_regs.h" // PCI_VENDOR_ID
14
15 // romlayout.S
16 extern void bios32_entry();
17 extern void pcibios32_entry();
18
19 #define RET_FUNC_NOT_SUPPORTED 0x81
20 #define RET_BAD_VENDOR_ID      0x83
21 #define RET_DEVICE_NOT_FOUND   0x86
22 #define RET_BUFFER_TOO_SMALL   0x89
23
24 // installation check
25 static void
26 handle_1ab101(struct bregs *regs)
27 {
28     // Find max bus.
29     int bdf, max;
30     foreachpci(bdf, max) {
31     }
32
33     regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
34     regs->bx = 0x0210; // PCI version 2.10
35     regs->cl = pci_bdf_to_bus(max - 1);
36     regs->edx = 0x20494350; // "PCI "
37     regs->edi = (u32)pcibios32_entry + BUILD_BIOS_ADDR;
38     set_code_success(regs);
39 }
40
41 // find pci device
42 static void
43 handle_1ab102(struct bregs *regs)
44 {
45     u32 id = (regs->cx << 16) | regs->dx;
46     int count = regs->si;
47     int bdf, max;
48     foreachpci(bdf, max) {
49         u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
50         if (v != id)
51             continue;
52         if (count--)
53             continue;
54         regs->bx = bdf;
55         set_code_success(regs);
56         return;
57     }
58     set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
59 }
60
61 // find class code
62 static void
63 handle_1ab103(struct bregs *regs)
64 {
65     int count = regs->si;
66     u32 classprog = regs->ecx;
67     int bdf, max;
68     foreachpci(bdf, max) {
69         u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
70         if ((v>>8) != classprog)
71             continue;
72         if (count--)
73             continue;
74         regs->bx = bdf;
75         set_code_success(regs);
76         return;
77     }
78     set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
79 }
80
81 // read configuration byte
82 static void
83 handle_1ab108(struct bregs *regs)
84 {
85     regs->cl = pci_config_readb(regs->bx, regs->di);
86     set_code_success(regs);
87 }
88
89 // read configuration word
90 static void
91 handle_1ab109(struct bregs *regs)
92 {
93     regs->cx = pci_config_readw(regs->bx, regs->di);
94     set_code_success(regs);
95 }
96
97 // read configuration dword
98 static void
99 handle_1ab10a(struct bregs *regs)
100 {
101     regs->ecx = pci_config_readl(regs->bx, regs->di);
102     set_code_success(regs);
103 }
104
105 // write configuration byte
106 static void
107 handle_1ab10b(struct bregs *regs)
108 {
109     pci_config_writeb(regs->bx, regs->di, regs->cl);
110     set_code_success(regs);
111 }
112
113 // write configuration word
114 static void
115 handle_1ab10c(struct bregs *regs)
116 {
117     pci_config_writew(regs->bx, regs->di, regs->cx);
118     set_code_success(regs);
119 }
120
121 // write configuration dword
122 static void
123 handle_1ab10d(struct bregs *regs)
124 {
125     pci_config_writel(regs->bx, regs->di, regs->ecx);
126     set_code_success(regs);
127 }
128
129 // get irq routing options
130 static void
131 handle_1ab10e(struct bregs *regs)
132 {
133     struct pir_header *pirtable_g = (void*)(GET_GLOBAL(PirOffset) + 0);
134     if (! pirtable_g) {
135         set_code_invalid(regs, RET_FUNC_NOT_SUPPORTED);
136         return;
137     }
138
139     struct param_s {
140         u16 size;
141         u16 buf_off;
142         u16 buf_seg;
143     } *param_far = (void*)(regs->di+0);
144
145     // Validate and update size.
146     u16 bufsize = GET_FARVAR(regs->es, param_far->size);
147     u16 pirsize = GET_GLOBAL(pirtable_g->size) - sizeof(struct pir_header);
148     SET_FARVAR(regs->es, param_far->size, pirsize);
149     if (bufsize < pirsize) {
150         set_code_invalid(regs, RET_BUFFER_TOO_SMALL);
151         return;
152     }
153
154     // Get dest buffer.
155     void *buf_far = (void*)(GET_FARVAR(regs->es, param_far->buf_off)+0);
156     u16 buf_seg = GET_FARVAR(regs->es, param_far->buf_seg);
157
158     // Memcpy pir table slots to dest buffer.
159     memcpy_far(buf_seg, buf_far
160                , get_global_seg()
161                , (void*)(pirtable_g->slots) + get_global_offset()
162                , pirsize);
163
164     // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
165     regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs);
166     set_code_success(regs);
167 }
168
169 static void
170 handle_1ab1XX(struct bregs *regs)
171 {
172     set_code_unimplemented(regs, RET_FUNC_NOT_SUPPORTED);
173 }
174
175 void
176 handle_1ab1(struct bregs *regs)
177 {
178     //debug_stub(regs);
179
180     if (! CONFIG_PCIBIOS) {
181         set_invalid(regs);
182         return;
183     }
184
185     switch (regs->al) {
186     case 0x01: handle_1ab101(regs); break;
187     case 0x02: handle_1ab102(regs); break;
188     case 0x03: handle_1ab103(regs); break;
189     case 0x08: handle_1ab108(regs); break;
190     case 0x09: handle_1ab109(regs); break;
191     case 0x0a: handle_1ab10a(regs); break;
192     case 0x0b: handle_1ab10b(regs); break;
193     case 0x0c: handle_1ab10c(regs); break;
194     case 0x0d: handle_1ab10d(regs); break;
195     case 0x0e: handle_1ab10e(regs); break;
196     default:   handle_1ab1XX(regs); break;
197     }
198 }
199
200
201 /****************************************************************
202  * 32bit interface
203  ****************************************************************/
204
205 #if MODE16 == 0 && MODESEGMENT == 1
206 // Entry point for 32bit pci bios functions.
207 void VISIBLE32SEG
208 handle_pcibios32(struct bregs *regs)
209 {
210     debug_enter(regs, DEBUG_HDL_pcibios32);
211     handle_1ab1(regs);
212 }
213 #endif
214
215 struct bios32_s {
216     u32 signature;
217     u32 entry;
218     u8 version;
219     u8 length;
220     u8 checksum;
221     u8 reserved[5];
222 } PACKED;
223
224 struct bios32_s BIOS32HEADER __aligned(16) VAR16EXPORT = {
225     .signature = 0x5f32335f, // _32_
226     .length = sizeof(BIOS32HEADER) / 16,
227 };
228
229 void
230 bios32_setup(void)
231 {
232     dprintf(3, "init bios32\n");
233
234     BIOS32HEADER.entry = (u32)bios32_entry;
235     BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER));
236 }