summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/bios32.c
blob: 257f018f34c440240f7f6b81749a7e679663b833 (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
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

#define VFLAG(...)	if(vflag) print(__VA_ARGS__)

#define UPTR2INT(p)	((uintptr)(p))

#define l16get(p)	(((p)[1]<<8)|(p)[0])
#define l32get(p)	(((u32int)l16get(p+2)<<16)|l16get(p))

static int vflag = 0;

typedef struct BIOS32sdh {		/* BIOS32 Service Directory Header */
	u8int	signature[4];		/* "_32_" */
	u8int	physaddr[4];		/* physical address of entry point */
	u8int	revision;
	u8int	length;			/* of header in paragraphs */
	u8int	checksum;		/* */
	u8int	reserved[5];
} BIOS32sdh;

typedef struct BIOS32si {		/* BIOS32 Service Interface */
	u8int*	base;			/* base address of service */
	int	length;			/* length of service */
	u32int	offset;			/* service entry-point from base */

	u16int	ptr[3];			/* far pointer m16:32 */
} BIOS32si;

static Lock bios32lock;
static u16int bios32ptr[3];
static void* bios32entry;

int
bios32ci(BIOS32si* si, BIOS32ci* ci)
{
	int r;

	lock(&bios32lock);
	r = bios32call(ci, si->ptr);
	unlock(&bios32lock);

	return r;
}

static int
bios32locate(void)
{
	uintptr ptr;
	BIOS32sdh *sdh;

	VFLAG("bios32link\n");
	if((sdh = sigsearch("_32_", sizeof(BIOS32sdh))) == nil)
		return -1;
	VFLAG("sdh @ %#p, entry %#ux\n", sdh, l32get(sdh->physaddr));

	bios32entry = vmap(l32get(sdh->physaddr), 4096+1);
	VFLAG("entry @ %#p\n", bios32entry);
	ptr = UPTR2INT(bios32entry);
	bios32ptr[0] = ptr & 0xffff;
	bios32ptr[1] = (ptr>>16) & 0xffff;
	bios32ptr[2] = KESEL;
	VFLAG("bios32link: ptr %ux %ux %ux\n",
		bios32ptr[0], bios32ptr[1], bios32ptr[2]);

	return 0;
}

void
BIOS32close(BIOS32si* si)
{
	vunmap(si->base, si->length);
	free(si);
}

BIOS32si*
bios32open(char* id)
{
	uint ptr;
	BIOS32ci ci;
	BIOS32si *si;

	lock(&bios32lock);
	if(bios32ptr[2] == 0 && bios32locate() < 0){
		unlock(&bios32lock);
		return nil;
	}

	VFLAG("bios32si: %s\n", id);
	memset(&ci, 0, sizeof(BIOS32ci));
	ci.eax = (id[3]<<24|(id[2]<<16)|(id[1]<<8)|id[0]);

	bios32call(&ci, bios32ptr);
	unlock(&bios32lock);

	VFLAG("bios32si: eax %ux\n", ci.eax);
	if(ci.eax & 0xff)
		return nil;
	VFLAG("bios32si: base %#ux length %#ux offset %#ux\n",
		ci.ebx, ci.ecx, ci.edx);

	if((si = malloc(sizeof(BIOS32si))) == nil)
		return nil;
	if((si->base = vmap(ci.ebx, ci.ecx)) == nil){
		free(si);
		return nil;
	}
	si->length = ci.ecx;

	ptr = UPTR2INT(si->base)+ci.edx;
	si->ptr[0] = ptr & 0xffff;
	si->ptr[1] = (ptr>>16) & 0xffff;
	si->ptr[2] = KESEL;
	VFLAG("bios32si: eax entry %ux\n", ptr);

	return si;
}