summaryrefslogtreecommitdiff
path: root/arch/x86/lib/bios_interrupts.c
blob: fdd966b2c846f0e05aa5cd021464873c03e13180 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// SPDX-License-Identifier: GPL-2.0
/*
 * From Coreboot
 *
 * Copyright (C) 2001 Ronald G. Minnich
 * Copyright (C) 2005 Nick.Barker9@btinternet.com
 * Copyright (C) 2007-2009 coresystems GmbH
 */

#include <common.h>
#include <asm/pci.h>
#include "bios_emul.h"

/* errors go in AH. Just set these up so that word assigns will work */
enum {
	PCIBIOS_SUCCESSFUL = 0x0000,
	PCIBIOS_UNSUPPORTED = 0x8100,
	PCIBIOS_BADVENDOR = 0x8300,
	PCIBIOS_NODEV = 0x8600,
	PCIBIOS_BADREG = 0x8700
};

int int10_handler(void)
{
	static u8 cursor_row, cursor_col;
	int res = 0;

	switch ((M.x86.R_EAX & 0xff00) >> 8) {
	case 0x01: /* Set cursor shape */
		res = 1;
		break;
	case 0x02: /* Set cursor position */
		if (cursor_row != ((M.x86.R_EDX >> 8) & 0xff) ||
		    cursor_col >= (M.x86.R_EDX & 0xff)) {
			debug("\n");
		}
		cursor_row = (M.x86.R_EDX >> 8) & 0xff;
		cursor_col = M.x86.R_EDX & 0xff;
		res = 1;
		break;
	case 0x03: /* Get cursor position */
		M.x86.R_EAX &= 0x00ff;
		M.x86.R_ECX = 0x0607;
		M.x86.R_EDX = (cursor_row << 8) | cursor_col;
		res = 1;
		break;
	case 0x06: /* Scroll up */
		debug("\n");
		res = 1;
		break;
	case 0x08: /* Get Character and Mode at Cursor Position */
		M.x86.R_EAX = 0x0f00 | 'A'; /* White on black 'A' */
		res = 1;
		break;
	case 0x09: /* Write Character and attribute */
	case 0x0e: /* Write Character */
		debug("%c", M.x86.R_EAX & 0xff);
		res = 1;
		break;
	case 0x0f: /* Get video mode */
		M.x86.R_EAX = 0x5002; /*80 x 25 */
		M.x86.R_EBX &= 0x00ff;
		res = 1;
		break;
	default:
		printf("Unknown INT10 function %04x\n", M.x86.R_EAX & 0xffff);
		break;
	}
	return res;
}

int int12_handler(void)
{
	M.x86.R_EAX = 64 * 1024;
	return 1;
}

int int16_handler(void)
{
	int res = 0;

	switch ((M.x86.R_EAX & 0xff00) >> 8) {
	case 0x00: /* Check for Keystroke */
		M.x86.R_EAX = 0x6120; /* Space Bar, Space */
		res = 1;
		break;
	case 0x01: /* Check for Keystroke */
		M.x86.R_EFLG |= 1 << 6; /* Zero Flag set (no key available) */
		res = 1;
		break;
	default:
		printf("Unknown INT16 function %04x\n", M.x86.R_EAX & 0xffff);

break;
	}
	return res;
}

#define PCI_CONFIG_SPACE_TYPE1	(1 << 0)
#define PCI_SPECIAL_CYCLE_TYPE1	(1 << 4)

int int1a_handler(void)
{
	unsigned short func = (unsigned short)M.x86.R_EAX;
	int retval = 1;
	unsigned short devid, vendorid, devfn;
	struct udevice *dev;
	/* Use short to get rid of gabage in upper half of 32-bit register */
	short devindex;
	unsigned char bus;
	pci_dev_t bdf;
	u32 dword;
	u16 word;
	u8 byte, reg;
	int ret;

	switch (func) {
	case 0xb101: /* PCIBIOS Check */
		M.x86.R_EDX = 0x20494350;	/* ' ICP' */
		M.x86.R_EAX &= 0xffff0000; /* Clear AH / AL */
		M.x86.R_EAX |= PCI_CONFIG_SPACE_TYPE1 |
				PCI_SPECIAL_CYCLE_TYPE1;
		/*
		 * last bus in the system. Hard code to 255 for now.
		 * dev_enumerate() does not seem to tell us (publically)
		 */
		M.x86.R_ECX = 0xff;
		M.x86.R_EDI = 0x00000000;	/* protected mode entry */
		retval = 1;
		break;
	case 0xb102: /* Find Device */
		devid = M.x86.R_ECX;
		vendorid = M.x86.R_EDX;
		devindex = M.x86.R_ESI;
		bdf = -1;
		ret = dm_pci_find_device(vendorid, devid, devindex, &dev);
		if (!ret) {
			unsigned short busdevfn;

			bdf = dm_pci_get_bdf(dev);
			M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
			M.x86.R_EAX |= PCIBIOS_SUCCESSFUL;
			/*
			 * busnum is an unsigned char;
			 * devfn is an int, so we mask it off.
			 */
			busdevfn = (PCI_BUS(bdf) << 8) | PCI_DEV(bdf) << 3 |
				PCI_FUNC(bdf);
			debug("0x%x: return 0x%x\n", func, busdevfn);
			M.x86.R_EBX = busdevfn;
			retval = 1;
		} else {
			M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
			M.x86.R_EAX |= PCIBIOS_NODEV;
			retval = 0;
		}
		break;
	case 0xb10a: /* Read Config Dword */
	case 0xb109: /* Read Config Word */
	case 0xb108: /* Read Config Byte */
	case 0xb10d: /* Write Config Dword */
	case 0xb10c: /* Write Config Word */
	case 0xb10b: /* Write Config Byte */
		devfn = M.x86.R_EBX & 0xff;
		bus = M.x86.R_EBX >> 8;
		reg = M.x86.R_EDI;
		bdf = PCI_BDF(bus, devfn >> 3, devfn & 7);

		ret = dm_pci_bus_find_bdf(bdf, &dev);
		if (ret) {
			debug("%s: Device %x not found\n", __func__, bdf);
			break;
		}

		switch (func) {
		case 0xb108: /* Read Config Byte */
			dm_pci_read_config8(dev, reg, &byte);
			M.x86.R_ECX = byte;
			break;
		case 0xb109: /* Read Config Word */
			dm_pci_read_config16(dev, reg, &word);
			M.x86.R_ECX = word;
			break;
		case 0xb10a: /* Read Config Dword */
			dm_pci_read_config32(dev, reg, &dword);
			M.x86.R_ECX = dword;
			break;
		case 0xb10b: /* Write Config Byte */
			byte = M.x86.R_ECX;
			dm_pci_write_config8(dev, reg, byte);
			break;
		case 0xb10c: /* Write Config Word */
			word = M.x86.R_ECX;
			dm_pci_write_config16(dev, reg, word);
			break;
		case 0xb10d: /* Write Config Dword */
			dword = M.x86.R_ECX;
			dm_pci_write_config32(dev, reg, dword);
			break;
		}
#ifdef CONFIG_REALMODE_DEBUG
		debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", func,
		      bus, devfn, reg, M.x86.R_ECX);
#endif
		M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
		M.x86.R_EAX |= PCIBIOS_SUCCESSFUL;
		retval = 1;
		break;
	default:
		printf("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
		M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
		M.x86.R_EAX |= PCIBIOS_UNSUPPORTED;
		retval = 0;
		break;
	}

	return retval;
}