diff options
| author | Jonathan Lemon <jlemon@FreeBSD.org> | 1999-04-15 21:01:14 +0000 |
|---|---|---|
| committer | Jonathan Lemon <jlemon@FreeBSD.org> | 1999-04-15 21:01:14 +0000 |
| commit | 039a180f50c7649bf7a9ac29a5fd14a6fcc3e94c (patch) | |
| tree | bfcdf5691f83bd142d1a0fb405a9d22261523cf5 /sys | |
| parent | 34d443c011b0f1b7d6b810cb2d99d9a5ac3a3d27 (diff) | |
Notes
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/i386/i386/vm86.c | 188 | ||||
| -rw-r--r-- | sys/i386/i386/vm86bios.s | 16 | ||||
| -rw-r--r-- | sys/i386/include/vm86.h | 24 | ||||
| -rw-r--r-- | sys/i386/isa/vesa.c | 48 |
4 files changed, 186 insertions, 90 deletions
diff --git a/sys/i386/i386/vm86.c b/sys/i386/i386/vm86.c index c8d0be1c7203..55c435e04fae 100644 --- a/sys/i386/i386/vm86.c +++ b/sys/i386/i386/vm86.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: vm86.c,v 1.19 1998/12/07 21:58:19 archie Exp $ + * $Id: vm86.c,v 1.23 1999/03/18 18:43:03 jlemon Exp $ */ #include "opt_vm86.h" @@ -450,17 +450,56 @@ vm86_initialize(void) vm86pcb = pcb; } +vm_offset_t +vm86_getpage(struct vm86context *vmc, int pagenum) +{ + int i; + + for (i = 0; i < vmc->npages; i++) + if (vmc->pmap[i].pte_num == pagenum) + return (vmc->pmap[i].kva); + return (0); +} + +vm_offset_t +vm86_addpage(struct vm86context *vmc, int pagenum, vm_offset_t kva) +{ + int i, flags = 0; + + for (i = 0; i < vmc->npages; i++) + if (vmc->pmap[i].pte_num == pagenum) + goto bad; + + if (vmc->npages == VM86_PMAPSIZE) + goto bad; /* XXX grow map? */ + + if (kva == 0) { + kva = (vm_offset_t)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + flags = VMAP_MALLOC; + } + + i = vmc->npages++; + vmc->pmap[i].flags = flags; + vmc->pmap[i].kva = kva; + vmc->pmap[i].pte_num = pagenum; + return (kva); +bad: + panic("vm86_addpage: not enough room, or overlap"); +} + void initial_bioscalls(u_int *basemem, u_int *extmem) { int i, method; struct vm86frame vmf; + struct vm86context vmc; u_int64_t highwat = 0; + pt_entry_t pte; struct { u_int64_t base; u_int64_t length; u_int32_t type; - } smap; + } *smap; bzero(&vmf, sizeof(struct vm86frame)); /* safety */ vm86_initialize(); @@ -474,9 +513,48 @@ initial_bioscalls(u_int *basemem, u_int *extmem) * if basemem != 640, map pages r/w into vm86 page table so * that the bios can scribble on it. */ - for (i = *basemem / 4; i < 160; i++) { - u_int *pte = (u_int *)vm86paddr; + pte = (pt_entry_t)vm86paddr; + for (i = *basemem / 4; i < 160; i++) pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; + + /* + * map page 1 R/W into the kernel page table so we can use it + * as a buffer. The kernel will unmap this page later. + */ + pte = (pt_entry_t)vtopte(KERNBASE + (1 << PAGE_SHIFT)); + *pte = (1 << PAGE_SHIFT) | PG_RW | PG_V; + + /* + * get memory map with INT 15:E820 + */ +#define SMAPSIZ sizeof(*smap) +#define SMAP_SIG 0x534D4150 /* 'SMAP' */ + + vmc.npages = 0; + smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT)); + vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); + + vmf.vmf_ebx = 0; + do { + vmf.vmf_eax = 0xE820; + vmf.vmf_edx = SMAP_SIG; + vmf.vmf_ecx = SMAPSIZ; + i = vm86_datacall(0x15, &vmf, &vmc); + if (i || vmf.vmf_eax != SMAP_SIG) + break; + if (smap->type == 0x01 && smap->base >= highwat) { + *extmem += (smap->length / 1024); + highwat = smap->base + smap->length; + } + } while (vmf.vmf_ebx != 0); + + if (*extmem != 0) { + if (*extmem > *basemem) { + *extmem -= *basemem; + method = 0xE820; + goto done; + } + printf("E820: extmem (%d) < basemem (%d)\n", *extmem, *basemem); } /* @@ -498,11 +576,6 @@ done: printf("BIOS basemem: %dK, extmem: %dK (from %#x call)\n", *basemem, *extmem, method); #endif /* !PC98 */ -#if 0 - /* VESA setup -- ? */ - vmf.vmf_ax = 0x4f02; - error = vm86_intcall(0x10, &vmf); -#endif } static void @@ -580,63 +653,76 @@ vm86_intcall(int intnum, struct vm86frame *vmf) } /* - * buffer must be entirely contained in a wired down page in kernel memory, - * and is mapped into page 1 in vm86 space. segment/offset will be filled - * in to create a vm86 pointer to the buffer. If intnum is a valid - * interrupt number (0-255), then the "interrupt trampoline" will be - * used, otherwise we use the caller's cs:ip routine. - * - * a future revision may allow multiple pages to be mapped, or allow - * the caller to pass in a custom page table to use. + * struct vm86context contains the page table to use when making + * vm86 calls. If intnum is a valid interrupt number (0-255), then + * the "interrupt trampoline" will be used, otherwise we use the + * caller's cs:ip routine. */ int -vm86_datacall(intnum, vmf, buffer, buflen, segment, offset) +vm86_datacall(intnum, vmf, vmc) int intnum; struct vm86frame *vmf; - char *buffer; - int buflen; - u_short *segment, *offset; + struct vm86context *vmc; { - int ret; + pt_entry_t pte = (pt_entry_t)vm86paddr; u_int page; - static u_char *buf; + int i, entry, retval; - if (buflen < 0 || buflen > PAGE_SIZE) - return(-1); + for (i = 0; i < vmc->npages; i++) { + page = vtophys(vmc->pmap[i].kva & PG_FRAME); + entry = vmc->pmap[i].pte_num; + vmc->pmap[i].old_pte = pte[entry]; + pte[entry] = page | PG_V | PG_RW | PG_U; + } - if (buf == NULL) { - buf = (u_char *)contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK, - 0ul, ~0ul, PAGE_SIZE, 0); - if (buf == NULL) - return(-1); + vmf->vmf_trapno = intnum; + retval = vm86_bioscall(vmf); + + for (i = 0; i < vmc->npages; i++) { + entry = vmc->pmap[i].pte_num; + pte[entry] = vmc->pmap[i].old_pte; } - *offset = 0; - *segment = 0x100; + return (retval); +} - bcopy((void *)buffer, (void *)buf, (size_t)buflen); - page = (u_int)buf & PG_FRAME; - page = vtophys(page); - vmf->vmf_trapno = page | (intnum & PAGE_MASK); - ret = vm86_bioscall(vmf); - bcopy((void *)buf, (void *)buffer, (size_t)buflen); +vm_offset_t +vm86_getaddr(vmc, sel, off) + struct vm86context *vmc; + u_short sel; + u_short off; +{ + int i, page; + vm_offset_t addr; - return ret; + addr = (vm_offset_t)MAKE_ADDR(sel, off); + page = addr >> PAGE_SHIFT; + for (i = 0; i < vmc->npages; i++) + if (page == vmc->pmap[i].pte_num) + return (vmc->pmap[i].kva + (addr & PAGE_MASK)); + return (0); } -#if 0 int -vm86_datacall(int intnum, u_int kpage, struct vm86frame *vmf) +vm86_getptr(vmc, kva, sel, off) + struct vm86context *vmc; + vm_offset_t kva; + u_short *sel; + u_short *off; { - if (kpage & PAGE_MASK) - return (EINVAL); - kpage = vtophys(kpage); + int i; - vmf->vmf_trapno = kpage | (intnum & PAGE_MASK); - return (vm86_bioscall(vmf)); + for (i = 0; i < vmc->npages; i++) + if (kva >= vmc->pmap[i].kva && + kva < vmc->pmap[i].kva + PAGE_SIZE) { + *off = kva - vmc->pmap[i].kva; + *sel = vmc->pmap[i].pte_num << 8; + return (1); + } + return (0); + panic("vm86_getptr: address not found"); } -#endif - + int vm86_sysarch(p, args) struct proc *p; @@ -646,11 +732,11 @@ vm86_sysarch(p, args) struct i386_vm86_args ua; struct vm86_kernel *vm86; - if (error = copyin(args, &ua, sizeof(struct i386_vm86_args))) + if ((error = copyin(args, &ua, sizeof(struct i386_vm86_args))) != 0) return (error); if (p->p_addr->u_pcb.pcb_ext == 0) - if (error = i386_extend_pcb(p)) + if ((error = i386_extend_pcb(p)) != 0) return (error); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; @@ -658,7 +744,7 @@ vm86_sysarch(p, args) case VM86_INIT: { struct vm86_init_args sa; - if (error = copyin(ua.sub_args, &sa, sizeof(sa))) + if ((error = copyin(ua.sub_args, &sa, sizeof(sa))) != 0) return (error); if (cpu_feature & CPUID_VME) vm86->vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0); diff --git a/sys/i386/i386/vm86bios.s b/sys/i386/i386/vm86bios.s index ce53bcf25776..3a1d4b30585d 100644 --- a/sys/i386/i386/vm86bios.s +++ b/sys/i386/i386/vm86bios.s @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: vm86bios.s,v 1.6 1998/09/29 18:01:18 jlemon Exp $ + * $Id: vm86bios.s,v 1.7 1998/10/01 20:45:28 jlemon Exp $ */ #include "opt_vm86.h" @@ -95,18 +95,6 @@ ENTRY(vm86_bioscall) rep movsl /* copy frame to new stack */ - movl TF_TRAPNO(%ebx),%ebx - cmpl $256,%ebx - jb 1f /* no page frame to map */ - - andl $~PAGE_MASK,%ebx -#if 0 - orl $PG_V|PG_RW|PG_U,%ebx /* XXX assembler error?? */ -#endif - orl $0x7,%ebx - movl SCR_PGTABLE(%edx),%eax /* va of vm86 page table */ - movl %ebx,4(%eax) /* set vm86 PTE entry 1 */ -1: movl _curpcb,%eax pushl %eax /* save curpcb */ movl %edx,_curpcb /* set curpcb to vm86pcb */ @@ -194,8 +182,6 @@ ENTRY(vm86_biosret) movl %eax,%cr3 /* install old page table */ movl $0,_in_vm86call /* reset trapflag */ - movl SCR_PGTABLE(%edx),%ebx /* va of vm86 page table */ - movl $0,4(%ebx) /* ...clear entry 1 */ movl _my_tr,%esi leal _gdt(,%esi,8),%ebx /* entry in GDT */ diff --git a/sys/i386/include/vm86.h b/sys/i386/include/vm86.h index c7fb23e42acb..0862f49cf629 100644 --- a/sys/i386/include/vm86.h +++ b/sys/i386/include/vm86.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: vm86.h,v 1.7 1998/07/14 17:13:23 msmith Exp $ + * $Id: vm86.h,v 1.8 1998/09/29 09:06:00 bde Exp $ */ #ifndef _MACHINE_VM86_H_ @@ -98,6 +98,19 @@ struct vm86frame { #define vmf_eflags eflags.r_ex }; +#define VM86_PMAPSIZE 3 +#define VMAP_MALLOC 1 /* page was malloced by us */ + +struct vm86context { + int npages; + struct vm86pmap { + int flags; + int pte_num; + vm_offset_t kva; + u_int old_pte; + } pmap[VM86_PMAPSIZE]; +}; + #define VM_USERCHANGE (PSL_USERCHANGE | PSL_RF) #define VME_USERCHANGE (VM_USERCHANGE | PSL_VIP | PSL_VIF) @@ -142,8 +155,13 @@ extern int vm86_emulate __P((struct vm86frame *)); extern int vm86_sysarch __P((struct proc *, char *)); extern void vm86_trap __P((struct vm86frame *)); extern int vm86_intcall __P((int, struct vm86frame *)); -extern int vm86_datacall __P((int, struct vm86frame *, char *, int, - u_short *, u_short *)); +extern int vm86_datacall __P((int, struct vm86frame *, struct vm86context *)); extern void initial_bioscalls __P((u_int *, u_int *)); +extern vm_offset_t vm86_getpage __P((struct vm86context *, int)); +extern vm_offset_t vm86_addpage __P((struct vm86context *, int, vm_offset_t)); +extern int vm86_getptr __P((struct vm86context *, vm_offset_t, + u_short *, u_short *)); + +extern vm_offset_t vm86_getaddr __P((struct vm86context *, u_short, u_short)); #endif /* _MACHINE_VM86_H_ */ diff --git a/sys/i386/isa/vesa.c b/sys/i386/isa/vesa.c index 51de263fa5a9..346e9b988b21 100644 --- a/sys/i386/isa/vesa.c +++ b/sys/i386/isa/vesa.c @@ -23,7 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: vesa.c,v 1.15.2.2 1999/02/20 03:06:04 yokota Exp $ + * $Id: vesa.c,v 1.15.2.3 1999/03/29 15:11:47 yokota Exp $ */ #include "vga.h" @@ -101,6 +101,7 @@ static vi_set_hw_cursor_t vesa_set_hw_cursor; static vi_set_hw_cursor_shape_t vesa_set_hw_cursor_shape; static vi_mmap_t vesa_mmap; static vi_diag_t vesa_diag; +static struct vm86context vesa_vmcontext; static video_switch_t vesavidsw = { vesa_probe, @@ -205,15 +206,16 @@ static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode) { struct vm86frame vmf; - u_char buf[256]; + u_char *buf; int err; bzero(&vmf, sizeof(vmf)); - bzero(buf, sizeof(buf)); vmf.vmf_eax = 0x4f01; vmf.vmf_ecx = mode; - err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf), - &vmf.vmf_es, &vmf.vmf_di); + buf = (u_char *)vm86_getpage(&vesa_vmcontext, 1); + vm86_getptr(&vesa_vmcontext, buf, &vmf.vmf_es, &vmf.vmf_di); + + err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); if ((err != 0) || (vmf.vmf_eax != 0x4f)) return 1; bcopy(buf, vmode, sizeof(*vmode)); @@ -271,18 +273,17 @@ vesa_bios_save_palette(int start, int colors, u_char *palette, int bits) int err; int i; - p = malloc(colors*4, M_DEVBUF, M_WAITOK); - bzero(&vmf, sizeof(vmf)); vmf.vmf_eax = 0x4f09; vmf.vmf_ebx = 1; /* get primary palette data */ vmf.vmf_ecx = colors; vmf.vmf_edx = start; - err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di); - if ((err != 0) || (vmf.vmf_eax != 0x4f)) { - free(p, M_DEVBUF); + p = (u_char *)vm86_getpage(&vesa_vmcontext, 1); + vm86_getptr(&vesa_vmcontext, p, &vmf.vmf_es, &vmf.vmf_di); + + err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); + if ((err != 0) || (vmf.vmf_eax != 0x4f)) return 1; - } bits = 8 - bits; for (i = 0; i < colors; ++i) { @@ -290,7 +291,6 @@ vesa_bios_save_palette(int start, int colors, u_char *palette, int bits) palette[i*3 + 1] = p[i*4 + 1] << bits; palette[i*3 + 2] = p[i*4] << bits; } - free(p, M_DEVBUF); return 0; } @@ -302,7 +302,7 @@ vesa_bios_load_palette(int start, int colors, u_char *palette, int bits) int err; int i; - p = malloc(colors*4, M_DEVBUF, M_WAITOK); + p = (u_char *)vm86_getpage(&vesa_vmcontext, 1); bits = 8 - bits; for (i = 0; i < colors; ++i) { p[i*4] = palette[i*3 + 2] >> bits; @@ -316,8 +316,9 @@ vesa_bios_load_palette(int start, int colors, u_char *palette, int bits) vmf.vmf_ebx = 0; /* set primary palette data */ vmf.vmf_ecx = colors; vmf.vmf_edx = start; - err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di); - free(p, M_DEVBUF); + vm86_getptr(&vesa_vmcontext, p, &vmf.vmf_es, &vmf.vmf_di); + + err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); return ((err != 0) || (vmf.vmf_eax != 0x4f)); } @@ -341,14 +342,18 @@ static int vesa_bios_save_restore(int code, void *p, size_t size) { struct vm86frame vmf; + u_char *buf; int err; bzero(&vmf, sizeof(vmf)); vmf.vmf_eax = 0x4f04; vmf.vmf_ecx = STATE_MOST; vmf.vmf_edx = code; /* STATE_SAVE/STATE_LOAD */ - err = vm86_datacall(0x10, &vmf, (char *)p, size, - &vmf.vmf_es, &vmf.vmf_bx); + buf = (u_char *)vm86_getpage(&vesa_vmcontext, 1); + vm86_getptr(&vesa_vmcontext, buf, &vmf.vmf_es, &vmf.vmf_di); + bcopy(p, buf, size); + + err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); return ((err != 0) || (vmf.vmf_eax != 0x4f)); } @@ -427,9 +432,9 @@ static void static int vesa_bios_init(void) { - static u_char buf[512]; struct vm86frame vmf; struct vesa_mode vmode; + u_char *buf; int modes; int err; int i; @@ -441,12 +446,13 @@ vesa_bios_init(void) vesa_adp_info = NULL; vesa_vmode[0].vi_mode = EOT; + buf = (u_char *)vm86_addpage(&vesa_vmcontext, 1, 0); bzero(&vmf, sizeof(vmf)); /* paranoia */ - bzero(buf, sizeof(buf)); bcopy("VBE2", buf, 4); /* try for VBE2 data */ vmf.vmf_eax = 0x4f00; - err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf), - &vmf.vmf_es, &vmf.vmf_di); + vm86_getptr(&vesa_vmcontext, buf, &vmf.vmf_es, &vmf.vmf_di); + + err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); if ((err != 0) || (vmf.vmf_eax != 0x4f) || bcmp("VESA", buf, 4)) return 1; vesa_adp_info = (struct vesa_info *)buf; |
