blob: d156518a3c0464f2f785373fb50dfa3abe23fcf7 [file] [log] [blame]
Kevin O'Connord25810a2008-06-12 22:16:35 -04001// PCI BIOS (int 1a/b1) calls
Kevin O'Connora0dc2962008-03-16 14:29:32 -04002//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2002 MandrakeSoft S.A.
5//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05006// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connora0dc2962008-03-16 14:29:32 -04007
8#include "types.h" // u32
9#include "util.h" // handle_1ab1
10#include "pci.h" // pci_config_readl
Kevin O'Connor9521e262008-07-04 13:04:29 -040011#include "bregs.h" // struct bregs
12#include "biosvar.h" // GET_EBDA
Kevin O'Connor4132e022008-12-04 19:39:10 -050013#include "pci_regs.h" // PCI_VENDOR_ID
Kevin O'Connora0dc2962008-03-16 14:29:32 -040014
Kevin O'Connora0dc2962008-03-16 14:29:32 -040015#define RET_FUNC_NOT_SUPPORTED 0x81
16#define RET_BAD_VENDOR_ID 0x83
17#define RET_DEVICE_NOT_FOUND 0x86
18#define RET_BUFFER_TOO_SMALL 0x89
19
20// installation check
21static void
22handle_1ab101(struct bregs *regs)
23{
Kevin O'Connore6338322008-11-29 20:31:49 -050024 // Find max bus.
25 int bdf, max;
Kevin O'Connor4132e022008-12-04 19:39:10 -050026 foreachpci(bdf, max) {
Kevin O'Connore6338322008-11-29 20:31:49 -050027 }
28
Kevin O'Connorcde7a582008-08-17 11:08:46 -040029 regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
30 regs->bx = 0x0210; // PCI version 2.10
Kevin O'Connore6338322008-11-29 20:31:49 -050031 regs->cl = pci_bdf_to_bus(max - 1);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040032 regs->edx = 0x20494350; // "PCI "
33 // XXX - bochs bios code sets edi to point to 32bit code - but no
34 // reference to this in spec.
Kevin O'Connorcde7a582008-08-17 11:08:46 -040035 set_code_success(regs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040036}
37
38// find pci device
39static void
40handle_1ab102(struct bregs *regs)
41{
Kevin O'Connor4132e022008-12-04 19:39:10 -050042 u32 id = (regs->cx << 16) | regs->dx;
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050043 int count = regs->si;
Kevin O'Connor4132e022008-12-04 19:39:10 -050044 int bdf, max;
45 foreachpci(bdf, max) {
46 u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
47 if (v != id)
48 continue;
49 if (count--)
50 continue;
51 regs->bx = bdf;
52 set_code_success(regs);
53 return;
54 }
55 set_code_fail(regs, RET_DEVICE_NOT_FOUND);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040056}
57
58// find class code
59static void
60handle_1ab103(struct bregs *regs)
61{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050062 int count = regs->si;
Kevin O'Connor4132e022008-12-04 19:39:10 -050063 u32 classprog = regs->ecx;
64 int bdf, max;
65 foreachpci(bdf, max) {
66 u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
67 if ((v>>8) != classprog)
68 continue;
69 if (count--)
70 continue;
71 regs->bx = bdf;
72 set_code_success(regs);
73 return;
74 }
75 set_code_fail(regs, RET_DEVICE_NOT_FOUND);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040076}
77
78// read configuration byte
79static void
80handle_1ab108(struct bregs *regs)
81{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050082 regs->cl = pci_config_readb(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040083 set_code_success(regs);
84}
85
86// read configuration word
87static void
88handle_1ab109(struct bregs *regs)
89{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050090 regs->cx = pci_config_readw(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040091 set_code_success(regs);
92}
93
94// read configuration dword
95static void
96handle_1ab10a(struct bregs *regs)
97{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050098 regs->ecx = pci_config_readl(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040099 set_code_success(regs);
100}
101
102// write configuration byte
103static void
104handle_1ab10b(struct bregs *regs)
105{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500106 pci_config_writeb(regs->bx, regs->di, regs->cl);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400107 set_code_success(regs);
108}
109
110// write configuration word
111static void
112handle_1ab10c(struct bregs *regs)
113{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500114 pci_config_writew(regs->bx, regs->di, regs->cx);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400115 set_code_success(regs);
116}
117
118// write configuration dword
119static void
120handle_1ab10d(struct bregs *regs)
121{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500122 pci_config_writel(regs->bx, regs->di, regs->ecx);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400123 set_code_success(regs);
124}
125
126// get irq routing options
127static void
128handle_1ab10e(struct bregs *regs)
129{
Kevin O'Connor51358db2008-12-28 21:50:29 -0500130 struct pir_header *pirtable_g = (void*)(GET_GLOBAL(PirOffset) + 0);
131 if (! pirtable_g) {
Kevin O'Connor0f803e42008-05-24 23:07:16 -0400132 set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
133 return;
134 }
135
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400136 // Validate and update size.
137 u16 size = GET_FARVAR(regs->es, *(u16*)(regs->di+0));
Kevin O'Connor51358db2008-12-28 21:50:29 -0500138 u16 pirsize = (GET_GLOBAL(pirtable_g->size)
Kevin O'Connord25810a2008-06-12 22:16:35 -0400139 - sizeof(struct pir_header));
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400140 SET_FARVAR(regs->es, *(u16*)(regs->di+0), pirsize);
141 if (size < pirsize) {
142 set_code_fail(regs, RET_BUFFER_TOO_SMALL);
143 return;
144 }
145
146 // Get dest buffer.
Kevin O'Connord25810a2008-06-12 22:16:35 -0400147 u16 d = (GET_FARVAR(regs->es, *(u16*)(regs->di+2)) + 0);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400148 u16 destseg = GET_FARVAR(regs->es, *(u16*)(regs->di+4));
149
150 // Memcpy pir table slots to dest buffer.
Kevin O'Connor51358db2008-12-28 21:50:29 -0500151 memcpy_far(MAKE_FARPTR(destseg, d)
Kevin O'Connordfc18fc2009-01-19 12:53:10 -0500152 , MAKE_FARPTR(SEG_BIOS, pirtable_g->slots)
Kevin O'Connor51358db2008-12-28 21:50:29 -0500153 , pirsize);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400154
155 // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
Kevin O'Connor51358db2008-12-28 21:50:29 -0500156 regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400157 set_code_success(regs);
158}
159
160static void
161handle_1ab1XX(struct bregs *regs)
162{
163 set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
164}
165
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400166void
167handle_1ab1(struct bregs *regs)
168{
169 //debug_stub(regs);
170
171 if (! CONFIG_PCIBIOS) {
172 set_fail(regs);
173 return;
174 }
175
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400176 switch (regs->al) {
177 case 0x01: handle_1ab101(regs); break;
178 case 0x02: handle_1ab102(regs); break;
179 case 0x03: handle_1ab103(regs); break;
180 case 0x08: handle_1ab108(regs); break;
181 case 0x09: handle_1ab109(regs); break;
182 case 0x0a: handle_1ab10a(regs); break;
183 case 0x0b: handle_1ab10b(regs); break;
184 case 0x0c: handle_1ab10c(regs); break;
185 case 0x0d: handle_1ab10d(regs); break;
186 case 0x0e: handle_1ab10e(regs); break;
187 default: handle_1ab1XX(regs); break;
188 }
189}