blob: 65e4a18c0607ea7422fd7b5a64fce57af48dd21a [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//
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
Kevin O'Connor9521e262008-07-04 13:04:29 -040011#include "bregs.h" // struct bregs
12#include "biosvar.h" // GET_EBDA
Kevin O'Connora0dc2962008-03-16 14:29:32 -040013
Kevin O'Connora0dc2962008-03-16 14:29:32 -040014#define RET_FUNC_NOT_SUPPORTED 0x81
15#define RET_BAD_VENDOR_ID 0x83
16#define RET_DEVICE_NOT_FOUND 0x86
17#define RET_BUFFER_TOO_SMALL 0x89
18
19// installation check
20static void
21handle_1ab101(struct bregs *regs)
22{
Kevin O'Connorcde7a582008-08-17 11:08:46 -040023 regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
24 regs->bx = 0x0210; // PCI version 2.10
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050025 regs->cl = pci_bdf_to_bus(GET_VAR(CS, MaxBDF) - 1);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040026 regs->edx = 0x20494350; // "PCI "
27 // XXX - bochs bios code sets edi to point to 32bit code - but no
28 // reference to this in spec.
Kevin O'Connorcde7a582008-08-17 11:08:46 -040029 set_code_success(regs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040030}
31
32// find pci device
33static void
34handle_1ab102(struct bregs *regs)
35{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050036 int bdf = -1;
37 int count = regs->si;
38 do {
39 bdf = pci_find_device(regs->dx, regs->cx, bdf+1);
40 if (bdf < 0) {
41 set_code_fail(regs, RET_DEVICE_NOT_FOUND);
42 return;
43 }
44 } while (count--);
45
46 regs->bx = bdf;
Kevin O'Connor0f803e42008-05-24 23:07:16 -040047 set_code_success(regs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040048}
49
50// find class code
51static void
52handle_1ab103(struct bregs *regs)
53{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050054 int bdf = -1;
55 int count = regs->si;
56 do {
57 bdf = pci_find_classprog(regs->ecx, bdf+1);
58 if (bdf < 0) {
59 set_code_fail(regs, RET_DEVICE_NOT_FOUND);
60 return;
61 }
62 } while (count--);
63
64 regs->bx = bdf;
Kevin O'Connor0f803e42008-05-24 23:07:16 -040065 set_code_success(regs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040066}
67
68// read configuration byte
69static void
70handle_1ab108(struct bregs *regs)
71{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050072 regs->cl = pci_config_readb(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040073 set_code_success(regs);
74}
75
76// read configuration word
77static void
78handle_1ab109(struct bregs *regs)
79{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050080 regs->cx = pci_config_readw(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040081 set_code_success(regs);
82}
83
84// read configuration dword
85static void
86handle_1ab10a(struct bregs *regs)
87{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050088 regs->ecx = pci_config_readl(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040089 set_code_success(regs);
90}
91
92// write configuration byte
93static void
94handle_1ab10b(struct bregs *regs)
95{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050096 pci_config_writeb(regs->bx, regs->di, regs->cl);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040097 set_code_success(regs);
98}
99
100// write configuration word
101static void
102handle_1ab10c(struct bregs *regs)
103{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500104 pci_config_writew(regs->bx, regs->di, regs->cx);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400105 set_code_success(regs);
106}
107
108// write configuration dword
109static void
110handle_1ab10d(struct bregs *regs)
111{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500112 pci_config_writel(regs->bx, regs->di, regs->ecx);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400113 set_code_success(regs);
114}
115
116// get irq routing options
117static void
118handle_1ab10e(struct bregs *regs)
119{
Kevin O'Connorf782d602008-11-08 13:35:32 -0500120 struct pir_header *pirtable_far = GET_EBDA(pir_loc);
Kevin O'Connord25810a2008-06-12 22:16:35 -0400121 if (! pirtable_far) {
Kevin O'Connor0f803e42008-05-24 23:07:16 -0400122 set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
123 return;
124 }
125
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400126 // Validate and update size.
127 u16 size = GET_FARVAR(regs->es, *(u16*)(regs->di+0));
Kevin O'Connord25810a2008-06-12 22:16:35 -0400128 u16 pirsize = (GET_FARPTR(pirtable_far->size)
129 - sizeof(struct pir_header));
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400130 SET_FARVAR(regs->es, *(u16*)(regs->di+0), pirsize);
131 if (size < pirsize) {
132 set_code_fail(regs, RET_BUFFER_TOO_SMALL);
133 return;
134 }
135
136 // Get dest buffer.
Kevin O'Connord25810a2008-06-12 22:16:35 -0400137 u16 d = (GET_FARVAR(regs->es, *(u16*)(regs->di+2)) + 0);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400138 u16 destseg = GET_FARVAR(regs->es, *(u16*)(regs->di+4));
139
140 // Memcpy pir table slots to dest buffer.
Kevin O'Connor18b927e2008-08-29 21:14:36 -0400141 memcpy_far(MAKE_FARPTR(destseg, d), pirtable_far, pirsize);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400142
143 // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
Kevin O'Connord25810a2008-06-12 22:16:35 -0400144 regs->bx = GET_FARPTR(pirtable_far->exclusive_irqs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400145 set_code_success(regs);
146}
147
148static void
149handle_1ab1XX(struct bregs *regs)
150{
151 set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
152}
153
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400154void
155handle_1ab1(struct bregs *regs)
156{
157 //debug_stub(regs);
158
159 if (! CONFIG_PCIBIOS) {
160 set_fail(regs);
161 return;
162 }
163
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400164 switch (regs->al) {
165 case 0x01: handle_1ab101(regs); break;
166 case 0x02: handle_1ab102(regs); break;
167 case 0x03: handle_1ab103(regs); break;
168 case 0x08: handle_1ab108(regs); break;
169 case 0x09: handle_1ab109(regs); break;
170 case 0x0a: handle_1ab10a(regs); break;
171 case 0x0b: handle_1ab10b(regs); break;
172 case 0x0c: handle_1ab10c(regs); break;
173 case 0x0d: handle_1ab10d(regs); break;
174 case 0x0e: handle_1ab10e(regs); break;
175 default: handle_1ab1XX(regs); break;
176 }
177}