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