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