diff options
| author | Richard Purdie <rpurdie@rpsys.net> | 2006-10-31 15:51:14 +0000 |
|---|---|---|
| committer | Richard Purdie <rpurdie@rpsys.net> | 2006-10-31 15:51:14 +0000 |
| commit | 107e16ef26b39adda7c81f6685cb000aec2e7ac8 (patch) | |
| tree | e775be3f0abe85ea722db87703bfce2c253fb8d5 /packages | |
| parent | fcd0c98b96d5b27573f7ca346ba522ec8692ae6c (diff) | |
linux-oz-2.6: Add missing patch.
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/linux/linux-openzaurus-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch | 3089 |
1 files changed, 3089 insertions, 0 deletions
diff --git a/packages/linux/linux-openzaurus-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch b/packages/linux/linux-openzaurus-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch new file mode 100644 index 0000000000..188ce6094e --- /dev/null +++ b/packages/linux/linux-openzaurus-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch @@ -0,0 +1,3089 @@ +# Patch generated against a6047eef1c465c38aacfbdab193161b3f0cd144 +--- +# Documentation/fb/vesafb.txt | 250 ++++-- +# arch/i386/boot/video.S | 12 +# drivers/video/Kconfig | 56 + +# drivers/video/Makefile | 6 +# drivers/video/fbmem.c | 1 +# drivers/video/modedb.c | 1 +# drivers/video/vesafb-thread.c | 727 +++++++++++++++++++ +# drivers/video/vesafb-tng.c | 1598 ++++++++++++++++++++++++++++++++++++++++++ +# include/linux/sched.h | 2 +# include/video/vesa.h | 150 +++ +# kernel/fork.c | 35 +# mm/memory.c | 1 +# mm/mmap.c | 1 +# 13 files changed, 2748 insertions(+), 92 deletions(-) +# +--- linux-2.6.17.orig/Documentation/fb/vesafb.txt ++++ linux-2.6.17/Documentation/fb/vesafb.txt +@@ -2,16 +2,18 @@ + What is vesafb? + =============== + +-This is a generic driver for a graphic framebuffer on intel boxes. ++Vesafb is a generic framebuffer driver for x86 and x86_64 boxes. + +-The idea is simple: Turn on graphics mode at boot time with the help +-of the BIOS, and use this as framebuffer device /dev/fb0, like the m68k +-(and other) ports do. ++VESA BIOS Extensions Version 2.0 are required, because we need access to ++a linear frame buffer. VBE 3.0 is required if you want to use modes with a ++higher (than the standard 60 Hz) refresh rate. + +-This means we decide at boot time whenever we want to run in text or +-graphics mode. Switching mode later on (in protected mode) is +-impossible; BIOS calls work in real mode only. VESA BIOS Extensions +-Version 2.0 are required, because we need a linear frame buffer. ++The VESA framebuffer driver comes in two flavors - the standard 'vesafb' ++and 'vesafb-tng'. Vesafb-tng is available only on 32-bit x86 due to the ++technology it uses (vm86). Vesafb-tng has more features than vesafb ++(adjusting the refresh rate on VBE 3.0 compliant boards, switching the ++video mode without rebooting, selecting a mode by providing its ++modedb name, and more). + + Advantages: + +@@ -29,26 +31,35 @@ Disadvantages: + How to use it? + ============== + +-Switching modes is done using the vga=... boot parameter. Read +-Documentation/svga.txt for details. ++If you are running a 32-bit x86 system and you decide to use vesafb-tng, ++you can either compile the driver into the kernel or use it as a module. ++The graphics mode you want to use is in both cases specified using the ++standard modedb format. + +-You should compile in both vgacon (for text mode) and vesafb (for +-graphics mode). Which of them takes over the console depends on +-whenever the specified mode is text or graphics. ++If your system doesn't support vm86 calls, things get a little more tricky. ++Since on such systems you can't do BIOS calls from protected mode in which ++kernel runs, you have to decide at boot time whenever you want to run in text ++or in graphics mode. Switching mode later on is impossible. Switching modes ++is done using the vga=... boot parameter. Read Documentation/svga.txt for ++details. Below is a more detailed description of what to do on systems using ++the standard vesafb driver. + +-The graphic modes are NOT in the list which you get if you boot with +-vga=ask and hit return. The mode you wish to use is derived from the +-VESA mode number. Here are those VESA mode numbers: ++You should compile in both vgacon (for text mode) and vesafb (for graphics ++mode). Which of them takes over the console depends on whenever the ++specified mode is text or graphics. ++ ++The graphic modes are NOT in the list which you get if you boot with vga=ask ++and hit return. The mode you wish to use is derived from the VESA mode number. ++Here are those VESA mode numbers: + + | 640x480 800x600 1024x768 1280x1024 + ----+------------------------------------- +-256 | 0x101 0x103 0x105 0x107 +-32k | 0x110 0x113 0x116 0x119 +-64k | 0x111 0x114 0x117 0x11A +-16M | 0x112 0x115 0x118 0x11B ++256 | 0x101 0x103 0x105 0x107 ++32k | 0x110 0x113 0x116 0x119 ++64k | 0x111 0x114 0x117 0x11A ++16M | 0x112 0x115 0x118 0x11B + +-The video mode number of the Linux kernel is the VESA mode number plus +-0x200. ++The video mode number of the Linux kernel is the VESA mode number plus 0x200. + + Linux_kernel_mode_number = VESA_mode_number + 0x200 + +@@ -56,15 +67,15 @@ So the table for the Kernel mode numbers + + | 640x480 800x600 1024x768 1280x1024 + ----+------------------------------------- +-256 | 0x301 0x303 0x305 0x307 +-32k | 0x310 0x313 0x316 0x319 +-64k | 0x311 0x314 0x317 0x31A +-16M | 0x312 0x315 0x318 0x31B ++256 | 0x301 0x303 0x305 0x307 ++32k | 0x310 0x313 0x316 0x319 ++64k | 0x311 0x314 0x317 0x31A ++16M | 0x312 0x315 0x318 0x31B + +-To enable one of those modes you have to specify "vga=ask" in the +-lilo.conf file and rerun LILO. Then you can type in the desired +-mode at the "vga=ask" prompt. For example if you like to use +-1024x768x256 colors you have to say "305" at this prompt. ++To enable one of those modes you have to specify "vga=ask" in the lilo.conf ++file and rerun LILO. Then you can type in the desired mode at the "vga=ask" ++prompt. For example if you like to use 1024x768x256 colors you have to say ++"305" at this prompt. + + If this does not work, this might be because your BIOS does not support + linear framebuffers or because it does not support this mode at all. +@@ -72,11 +83,12 @@ Even if your board does, it might be the + Extensions v2.0 are required, 1.2 is NOT sufficient. You will get a + "bad mode number" message if something goes wrong. + +-1. Note: LILO cannot handle hex, for booting directly with ++1. Note: LILO cannot handle hex, for booting directly with + "vga=mode-number" you have to transform the numbers to decimal. + 2. Note: Some newer versions of LILO appear to work with those hex values, + if you set the 0x in front of the numbers. + ++ + X11 + === + +@@ -84,98 +96,164 @@ XF68_FBDev should work just fine, but it + another (accelerated) X-Server like XF86_SVGA might or might not work. + It depends on X-Server and graphics board. + +-The X-Server must restore the video mode correctly, else you end up ++The X-Server must restore the video mode correctly, or else you end up + with a broken console (and vesafb cannot do anything about this). ++With vesafb-tng chances are that the console will be restored properly ++even if the X server messes up the video mode. + + + Refresh rates + ============= + +-There is no way to change the vesafb video mode and/or timings after +-booting linux. If you are not happy with the 60 Hz refresh rate, you +-have these options: ++With VBE 3.0 compatible BIOSes and vesafb-tng it is possible to change ++the refresh rate either at boot time (by specifying the @<rr> part of ++the mode name) or later, using the fbset utility. + +- * configure and load the DOS-Tools for your the graphics board (if +- available) and boot linux with loadlin. +- * use a native driver (matroxfb/atyfb) instead if vesafb. If none ++If you want to use the default BIOS refresh rate while switching modes ++on a running system, set pixclock to 0. ++ ++With VBE 2.0 there is no way to change the mode timings after booting ++Linux. If you are not happy with the 60 Hz refresh rate, you have ++the following options: ++ ++ * Configure and load the DOS tools for your the graphics board (if ++ available) and boot Linux with loadlin. ++ * Use a native driver (matroxfb/atyfb) instead of vesafb. If none + is available, write a new one! +- * VBE 3.0 might work too. I have neither a gfx board with VBE 3.0 +- support nor the specs, so I have not checked this yet. ++ * Use a BIOS editor to change the default refresh rate (such an ++ editor does exist at least for ATI Radeon BIOSes). ++ * If you're running a non-vm86 and VBE 3.0 compatible system, you can ++ use a kernel patch (vesafb-rrc) to hard-code some mode timings in ++ the kernel and use these while setting the video mode at boot time. ++ ++Note that there are some boards (nVidia 59**, 57** and newer models) ++claiming that their Video BIOS is VBE 3.0 compliant, while ignoring the ++CRTC values provided by software such as vesafb-tng. You'll not be able ++to adjust the refresh rate if you're using one of these boards. + + + Configuration + ============= + +-The VESA BIOS provides protected mode interface for changing +-some parameters. vesafb can use it for palette changes and +-to pan the display. It is turned off by default because it +-seems not to work with some BIOS versions, but there are options +-to turn it on. ++The VESA BIOS provides protected mode interface for changing some parameters. ++vesafb can use it for palette changes and to pan the display. It is turned ++off by default because it seems not to work with some BIOS versions, but ++there are options to turn it on. + +-You can pass options to vesafb using "video=vesafb:option" on +-the kernel command line. Multiple options should be separated +-by comma, like this: "video=vesafb:ypan,invers" ++You can pass options to vesafb using "video=vesafb:option" on the kernel ++command line. Multiple options should be separated by a comma, like this: ++"video=vesafb:ypan,1024x768-32@85" + +-Accepted options: ++Note that vesafb-tng still uses the "video=vesafb:option" format of the ++kernel command line video parameter. "video=vesafb-tng:xxx" is incorrect. + +-invers no comment... ++Accepted options (both vesafb and vesafb-tng): + +-ypan enable display panning using the VESA protected mode +- interface. The visible screen is just a window of the +- video memory, console scrolling is done by changing the +- start of the window. +- pro: * scrolling (fullscreen) is fast, because there is +- no need to copy around data. +- * You'll get scrollback (the Shift-PgUp thing), +- the video memory can be used as scrollback buffer +- kontra: * scrolling only parts of the screen causes some +- ugly flicker effects (boot logo flickers for +- example). ++ypan Enable display panning using the VESA protected mode interface ++ The visible screen is just a window of the video memory, ++ console scrolling is done by changing the start of the window. ++ pro: * scrolling (fullscreen) is fast, because there is ++ no need to copy around data. ++ * you'll get scrollback (the Shift-PgUp thing), ++ the video memory can be used as scrollback buffer ++ con: * scrolling only parts of the screen causes some ++ ugly flicker effects (boot logo flickers for ++ example). + +-ywrap Same as ypan, but assumes your gfx board can wrap-around +- the video memory (i.e. starts reading from top if it +- reaches the end of video memory). Faster than ypan. ++ywrap Same as ypan, but assumes your gfx board can wrap-around the video ++ memory (i.e. starts reading from top if it reaches the end of ++ video memory). Faster than ypan. + +-redraw scroll by redrawing the affected part of the screen, this +- is the safe (and slow) default. ++redraw Scroll by redrawing the affected part of the screen, this is the ++ safe (and slow) default. + ++vgapal Use the standard VGA registers for palette changes. + +-vgapal Use the standard vga registers for palette changes. +- This is the default. +-pmipal Use the protected mode interface for palette changes. ++pmipal Use the protected mode interface for palette changes. ++ This is the default is the protected mode interface is available. + +-mtrr:n setup memory type range registers for the vesafb framebuffer +- where n: +- 0 - disabled (equivalent to nomtrr) (default) +- 1 - uncachable +- 2 - write-back +- 3 - write-combining +- 4 - write-through ++mtrr:n Setup memory type range registers for the vesafb framebuffer ++ where n: ++ 0 - disabled (equivalent to nomtrr) (default) ++ 1 - uncachable ++ 2 - write-back ++ 3 - write-combining ++ 4 - write-through + +- If you see the following in dmesg, choose the type that matches the +- old one. In this example, use "mtrr:2". ++ If you see the following in dmesg, choose the type that matches ++ the old one. In this example, use "mtrr:2". + ... + mtrr: type mismatch for e0000000,8000000 old: write-back new: write-combining + ... + +-nomtrr disable mtrr ++nomtrr Do not use memory type range registers for vesafb. + + vremap:n + remap 'n' MiB of video RAM. If 0 or not specified, remap memory +- according to video mode. (2.5.66 patch/idea by Antonino Daplas +- reversed to give override possibility (allocate more fb memory +- than the kernel would) to 2.4 by tmb@iki.fi) ++ according to video mode. (2.5.66 patch/idea by Antonino Daplas ++ reversed to give override possibility (allocate more fb memory ++ than the kernel would) to 2.4 by tmb@iki.fi) + + vtotal:n + if the video BIOS of your card incorrectly determines the total + amount of video RAM, use this option to override the BIOS (in MiB). + +-Have fun! ++Options accepted only by vesafb-tng: + +- Gerd ++<mode> The mode you want to set, in the standard modedb format. Refer to ++ modedb.txt for a detailed description. If you specify a mode that is ++ not supported by your board's BIOS, vesafb-tng will attempt to set a ++ similar mode. The list of supported modes can be found in ++ /proc/fbx/modes, where x is the framebuffer number (usually 0). ++ When vesafb-tng is compiled as a module, the mode string should be ++ provided as a value of the parameter 'mode'. ++ ++vbemode:x ++ Force the use of VBE mode x. The mode will only be set if it's ++ found in the VBE-provided list of supported modes. ++ NOTE: The mode number 'x' should be specified in VESA mode number ++ notation, not the Linux kernel one (eg. 257 instead of 769). ++ HINT: If you use this option because normal <mode> parameter does ++ not work for you and you use a X server, you'll probably want to ++ set the 'nocrtc' option to ensure that the video mode is properly ++ restored after console <-> X switches. ++ ++nocrtc Do not use CRTC timings while setting the video mode. This option ++ makes sence only with VBE 3.0 compliant systems. Use it if you have ++ problems with modes set in the standard way. Note that using this ++ option means that any refresh rate adjustments will be ignored ++ and the refresh rate will stay at your BIOS default (60 Hz). ++ ++noedid Do not try to fetch and use EDID-provided modes. ++ ++noblank Disable hardware blanking. ++ ++gtf Force the use of VESA's GTF (Generalized Timing Formula). Specifying ++ this will cause vesafb to skip its internal modedb and EDID-modedb ++ and jump straight to the GTF part of the code (normally used only if ++ everything else failed). This can be useful if you want to get as ++ much as possible from your graphics board but your BIOS doesn't ++ support modes with the refresh rates you require. Note that you may ++ need to specify the maxhf, maxvf and maxclk parameters if they are not ++ provided by the EDID block. ++ ++Additionally, the following parameters may be provided. They all override the ++EDID-provided values and BIOS defaults. Refer to your monitor's specs to get ++the correct values for maxhf, maxvf and maxclk for your hardware. ++ ++maxhf:n Maximum horizontal frequency (in kHz). ++maxvf:n Maximum vertical frequency (in Hz). ++maxclk:n Maximum pixel clock (in MHz). ++ ++Have fun! + + -- ++Original document for the vesafb driver by + Gerd Knorr <kraxel@goldbach.in-berlin.de> + +-Minor (mostly typo) changes +-by Nico Schmoigl <schmoigl@rumms.uni-mannheim.de> ++Minor (mostly typo) changes by ++Nico Schmoigl <schmoigl@rumms.uni-mannheim.de> ++ ++Extended documentation for vm86, VBE 3.0 and vesafb-tng by ++Michal Januszewski <spock@gentoo.org> ++ +--- linux-2.6.17.orig/arch/i386/boot/video.S ++++ linux-2.6.17/arch/i386/boot/video.S +@@ -165,10 +165,12 @@ basret: ret + # parameters in the default 80x25 mode -- these are set directly, + # because some very obscure BIOSes supply insane values. + mode_params: ++#ifdef CONFIG_FB_VESA_STD + #ifdef CONFIG_VIDEO_SELECT + cmpb $0, graphic_mode + jnz mopar_gr + #endif ++#endif + movb $0x03, %ah # Read cursor position + xorb %bh, %bh + int $0x10 +@@ -201,6 +203,7 @@ mopar2: movb %al, %fs:(PARAM_VIDEO_LINES + ret + + #ifdef CONFIG_VIDEO_SELECT ++#ifdef CONFIG_FB_VESA_STD + # Fetching of VESA frame buffer parameters + mopar_gr: + leaw modelist+1024, %di +@@ -283,6 +286,7 @@ dac_done: + movw %es, %fs:(PARAM_VESAPM_SEG) + movw %di, %fs:(PARAM_VESAPM_OFF) + no_pm: ret ++#endif + + # The video mode menu + mode_menu: +@@ -497,10 +501,12 @@ mode_set: + + cmpb $VIDEO_FIRST_V7>>8, %ah + jz setv7 +- ++ ++#ifdef CONFIG_FB_VESA_STD + cmpb $VIDEO_FIRST_VESA>>8, %ah + jnc check_vesa +- ++#endif ++ + orb %ah, %ah + jz setmenu + +@@ -572,6 +578,7 @@ setr1: lodsw + movw -4(%si), %ax # Fetch mode ID + jmp _m_s + ++#ifdef CONFIG_FB_VESA_STD + check_vesa: + leaw modelist+1024, %di + subb $VIDEO_FIRST_VESA>>8, %bh +@@ -605,6 +612,7 @@ check_vesa: + ret + + _setbad: jmp setbad # Ugly... ++#endif + + # Recalculate vertical display end registers -- this fixes various + # inconsistencies of extended modes on many adapters. Called when +--- linux-2.6.17.orig/drivers/video/Kconfig ++++ linux-2.6.17/drivers/video/Kconfig +@@ -472,8 +472,22 @@ config FB_TGA + cards. Say Y if you have one of those. + + config FB_VESA +- bool "VESA VGA graphics support" +- depends on (FB = y) && X86 ++ tristate "VESA VGA graphics support" ++ depends on (FB = y) && (X86 || X86_64) ++ help ++ This is the frame buffer device driver for generic VESA 2.0 ++ compliant graphic cards. The older VESA 1.2 cards are not supported. ++ You will get a boot time penguin logo at no additional cost. Please ++ read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. ++ ++choice ++ prompt "VESA driver type" ++ depends on FB_VESA ++ default FB_VESA_STD if X86_64 ++ default FB_VESA_TNG if X86 ++ ++config FB_VESA_STD ++ bool "vesafb" + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT +@@ -481,7 +495,43 @@ config FB_VESA + This is the frame buffer device driver for generic VESA 2.0 + compliant graphic cards. The older VESA 1.2 cards are not supported. + You will get a boot time penguin logo at no additional cost. Please +- read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. ++ read <file:Documentation/fb/vesafb.txt>. Choose this driver if you ++ are experiencing problems with vesafb-tng or if you own a 64-bit system. ++ ++ Note that this driver cannot be compiled as a module. ++ ++config FB_VESA_TNG ++ bool "vesafb-tng" ++ depends on !X86_64 ++ select FB_MODE_HELPERS ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ This is the frame buffer device driver for generic VESA 2.0 ++ compliant graphic cards. It is capable of taking advantage of ++ VBE 3.0 features. With this driver you will be able to adjust ++ the refresh rate (VBE 3.0 compliant boards only) and change ++ the graphic mode on-the-fly. ++ ++ You will also get a boot time penguin logo at no additional cost. Please ++ read <file:Documentation/fb/vesafb.txt>. ++ ++endchoice ++ ++config FB_VESA_DEFAULT_MODE ++ string "VESA default mode" ++ depends on FB_VESA_TNG ++ default "640x480@60" ++ help ++ This option is used to determine the default mode vesafb is ++ supposed to switch to in case no mode is provided as a kernel ++ command line parameter. ++ ++config VIDEO_SELECT ++ bool ++ depends on FB_VESA ++ default y + + config VIDEO_SELECT + bool +--- linux-2.6.17.orig/drivers/video/Makefile ++++ linux-2.6.17/drivers/video/Makefile +@@ -97,7 +97,11 @@ obj-$(CONFIG_FB_IMX) += imx + obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o + + # Platform or fallback drivers go here +-obj-$(CONFIG_FB_VESA) += vesafb.o ++ifeq ($(CONFIG_FB_VESA_STD),y) ++ obj-y += vesafb.o ++else ++ obj-$(CONFIG_FB_VESA) += vesafb-thread.o vesafb-tng.o ++endif + obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o + obj-$(CONFIG_FB_OF) += offb.o + +--- linux-2.6.17.orig/drivers/video/fbmem.c ++++ linux-2.6.17/drivers/video/fbmem.c +@@ -1438,6 +1438,7 @@ fbmem_init(void) + printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); + fb_class = NULL; + } ++ + return 0; + } + +--- linux-2.6.17.orig/drivers/video/modedb.c ++++ linux-2.6.17/drivers/video/modedb.c +@@ -671,6 +671,7 @@ void fb_var_to_videomode(struct fb_video + { + u32 pixclock, hfreq, htotal, vtotal; + ++ mode->refresh = 0; + mode->name = NULL; + mode->xres = var->xres; + mode->yres = var->yres; +--- /dev/null ++++ linux-2.6.17/drivers/video/vesafb-thread.c +@@ -0,0 +1,727 @@ ++/* ++ * Framebuffer driver for VBE 2.0+ compliant graphic boards. ++ * Kernel thread and vm86 routines. ++ * ++ * (c) 2004-2006 Michal Januszewski <spock@gentoo.org> ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/slab.h> ++#include <linux/workqueue.h> ++#include <linux/completion.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/signal.h> ++#include <linux/suspend.h> ++#include <linux/unistd.h> ++#include <video/vesa.h> ++#include <video/edid.h> ++#include <asm/mman.h> ++#include <asm/page.h> ++#include <asm/vm86.h> ++#include <asm/thread_info.h> ++#include <asm/uaccess.h> ++#include <asm/mmu_context.h> ++#include "edid.h" ++ ++#ifdef MODULE ++int errno; ++#endif ++ ++static DECLARE_COMPLETION(vesafb_th_completion); ++static DECLARE_MUTEX(vesafb_task_list_sem); ++static LIST_HEAD(vesafb_task_list); ++static DECLARE_WAIT_QUEUE_HEAD(vesafb_wait); ++ ++static struct vm86_struct vm86; ++static int vesafb_pid = 0; ++ ++_syscall3(int,ioperm,unsigned long, a, unsigned long, b, unsigned long, c); ++_syscall1(int,vm86old,struct vm86_struct __user*, v86); ++ ++#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK) ++#define VM86_PUSHW(x) \ ++do { \ ++ vm86.regs.esp -= 2; \ ++ *(u16*)(STACK_ADDR + vm86.regs.esp) = x; \ ++} while(0); ++ ++/* Stack, the return code and buffers will be put into ++ * one contiguous memory chunk: ++ * ++ * [ STACK | RET_CODE | BUFFER ] ++ * ++ * Some video BIOSes (sis6326) try to store data somewhere ++ * in 0x7000-0x7fff, so we zeromap more memory to be safe. ++ */ ++#define IVTBDA_SIZE PAGE_SIZE ++#define RET_CODE_SIZE 0x0010 ++#define STACK_SIZE 0x0500 ++#define BUFFER_SIZE 0x10000 ++ ++/* The amount of memory that will be allocated should be a multiple ++ * of PAGE_SIZE. */ ++#define __MEM_SIZE (RET_CODE_SIZE + STACK_SIZE + BUFFER_SIZE) ++#define REAL_MEM_SIZE (((__MEM_SIZE / PAGE_SIZE) + 1) * PAGE_SIZE) ++ ++#define IVTBDA_ADDR 0x00000 ++#define STACK_ADDR (IVTBDA_ADDR + IVTBDA_SIZE) ++#define RET_CODE_ADDR (STACK_ADDR + STACK_SIZE) ++#define BUF_ADDR (RET_CODE_ADDR + RET_CODE_SIZE) ++ ++#define FLAG_D (1 << 10) ++ ++/* Segment prefix opcodes */ ++enum { ++ P_CS = 0x2e, ++ P_SS = 0x36, ++ P_DS = 0x3e, ++ P_ES = 0x26, ++ P_FS = 0x64, ++ P_GS = 0x65 ++}; ++ ++/* Emulated vm86 ins instruction */ ++static void vm86_ins(int size) ++{ ++ u32 edx, edi; ++ edx = vm86.regs.edx & 0xffff; ++ edi = (vm86.regs.edi & 0xffff) + (u32)(vm86.regs.es << 4); ++ ++ if (vm86.regs.eflags & FLAG_D) ++ asm volatile ("std\n"); ++ else ++ asm volatile ("cld\n"); ++ ++ switch (size) { ++ case 4: ++ asm volatile ("insl\n" : "=D" (edi) : "d" (edx), "0" (edi)); ++ break; ++ case 2: ++ asm volatile ("insw\n" : "=D" (edi) : "d" (edx), "0" (edi)); ++ break; ++ case 1: ++ asm volatile ("insb\n" : "=D" (edi) : "d" (edx), "0" (edi)); ++ break; ++ } ++ ++ if (vm86.regs.eflags & FLAG_D) ++ asm volatile ("cld\n"); ++ ++ edi -= (u32)(vm86.regs.es << 4); ++ ++ vm86.regs.edi &= 0xffff0000; ++ vm86.regs.edi |= edi & 0xffff; ++} ++ ++static void vm86_rep_ins(int size) ++{ ++ u16 cx = vm86.regs.ecx; ++ while (cx--) ++ vm86_ins(size); ++ ++ vm86.regs.ecx &= 0xffff0000; ++} ++ ++/* Emulated vm86 outs instruction */ ++static void vm86_outs(int size, int segment) ++{ ++ u32 edx, esi, base; ++ ++ edx = vm86.regs.edx & 0xffff; ++ esi = vm86.regs.esi & 0xffff; ++ ++ switch (segment) { ++ case P_CS: base = vm86.regs.cs; break; ++ case P_SS: base = vm86.regs.ss; break; ++ case P_ES: base = vm86.regs.es; break; ++ case P_FS: base = vm86.regs.fs; break; ++ case P_GS: base = vm86.regs.gs; break; ++ default: base = vm86.regs.ds; break; ++ } ++ ++ esi += base << 4; ++ ++ if (vm86.regs.eflags & FLAG_D) ++ asm volatile ("std\n"); ++ else ++ asm volatile ("cld\n"); ++ ++ switch (size) { ++ case 4: ++ asm volatile ("outsl\n" : "=S" (esi) : "d" (edx), "0" (esi)); ++ break; ++ case 2: ++ asm volatile ("outsw\n" : "=S" (esi) : "d" (edx), "0" (esi)); ++ break; ++ case 1: ++ asm volatile ("outsb\n" : "=S" (esi) : "d" (edx), "0" (esi)); ++ break; ++ } ++ ++ if (vm86.regs.eflags & FLAG_D) ++ asm volatile ("cld"); ++ ++ esi -= base << 4; ++ vm86.regs.esi &= 0xffff0000; ++ vm86.regs.esi |= (esi & 0xffff); ++} ++ ++static void vm86_rep_outs(int size, int segment) ++{ ++ u16 cx = vm86.regs.ecx; ++ while (cx--) ++ vm86_outs(size, segment); ++ ++ vm86.regs.ecx &= 0xffff0000; ++} ++ ++static int vm86_do_unknown(void) ++{ ++ u8 data32 = 0, segment = P_DS, rep = 0; ++ u8 *instr; ++ int ret = 0, i = 0; ++ ++ instr = (u8*)((vm86.regs.cs << 4) + vm86.regs.eip); ++ ++ while (1) { ++ switch(instr[i]) { ++ case 0x66: /* operand size prefix */ ++ data32 = 1 - data32; ++ i++; ++ break; ++ case 0xf2: /* repnz */ ++ case 0xf3: /* rep */ ++ rep = 1; ++ i++; ++ break; ++ case P_CS: /* segment prefix */ ++ case P_SS: ++ case P_DS: ++ case P_ES: ++ case P_FS: ++ case P_GS: ++ segment = instr[i]; ++ i++; ++ break; ++ case 0xf0: /* LOCK - ignored */ ++ case 0x67: /* address size prefix - ignored */ ++ i++; ++ break; ++ case 0x6c: /* insb */ ++ if (rep) ++ vm86_rep_ins(1); ++ else ++ vm86_ins(1); ++ i++; ++ goto out; ++ case 0x6d: /* insw / insd */ ++ if (rep) { ++ if (data32) ++ vm86_rep_ins(4); ++ else ++ vm86_rep_ins(2); ++ } else { ++ if (data32) ++ vm86_ins(4); ++ else ++ vm86_ins(2); ++ } ++ i++; ++ goto out; ++ case 0x6e: /* outsb */ ++ if (rep) ++ vm86_rep_outs(1, segment); ++ else ++ vm86_outs(1, segment); ++ i++; ++ goto out; ++ case 0x6f: /* outsw / outsd */ ++ if (rep) { ++ if (data32) ++ vm86_rep_outs(4, segment); ++ else ++ vm86_rep_outs(2, segment); ++ } else { ++ if (data32) ++ vm86_outs(4, segment); ++ else ++ vm86_outs(2, segment); ++ } ++ i++; ++ goto out; ++ case 0xe4: /* inb xx */ ++ asm volatile ( ++ "inb %w1, %b0" ++ : "=a" (vm86.regs.eax) ++ : "d" (instr[i+1]), "0" (vm86.regs.eax)); ++ i += 2; ++ goto out; ++ case 0xe5: /* inw xx / ind xx */ ++ if (data32) { ++ asm volatile ( ++ "inl %w1, %0" ++ : "=a" (vm86.regs.eax) ++ : "d" (instr[i+1]), ++ "0" (vm86.regs.eax)); ++ } else { ++ asm volatile ( ++ "inw %w1, %w0" ++ : "=a" (vm86.regs.eax) ++ : "d" (instr[i+1]), ++ "0" (vm86.regs.eax)); ++ } ++ i += 2; ++ goto out; ++ ++ case 0xec: /* inb dx */ ++ asm volatile ( ++ "inb %w1, %b0" ++ : "=a" (vm86.regs.eax) ++ : "d" (vm86.regs.edx), "0" (vm86.regs.eax)); ++ i++; ++ goto out; ++ case 0xed: /* inw dx / ind dx */ ++ if (data32) { ++ asm volatile ( ++ "inl %w1, %0" ++ : "=a" (vm86.regs.eax) ++ : "d" (vm86.regs.edx)); ++ } else { ++ asm volatile ( ++ "inw %w1, %w0" ++ : "=a" (vm86.regs.eax) ++ : "d" (vm86.regs.edx)); ++ } ++ i++; ++ goto out; ++ case 0xe6: /* outb xx */ ++ asm volatile ( ++ "outb %b0, %w1" ++ : /* no return value */ ++ : "a" (vm86.regs.eax), "d" (instr[i+1])); ++ i += 2; ++ goto out; ++ case 0xe7: /* outw xx / outd xx */ ++ if (data32) { ++ asm volatile ( ++ "outl %0, %w1" ++ : /* no return value */ ++ : "a" (vm86.regs.eax), ++ "d" (instr[i+1])); ++ } else { ++ asm volatile ( ++ "outw %w0, %w1" ++ : /* no return value */ ++ : "a" (vm86.regs.eax), ++ "d" (instr[i+1])); ++ } ++ i += 2; ++ goto out; ++ case 0xee: /* outb dx */ ++ asm volatile ( ++ "outb %b0, %w1" ++ : /* no return value */ ++ : "a" (vm86.regs.eax), "d" (vm86.regs.edx)); ++ i++; ++ goto out; ++ case 0xef: /* outw dx / outd dx */ ++ if (data32) { ++ asm volatile ( ++ "outl %0, %w1" ++ : /* no return value */ ++ : "a" (vm86.regs.eax), ++ "d" (vm86.regs.edx)); ++ } else { ++ asm volatile ( ++ "outw %w0, %w1" ++ : /* no return value */ ++ : "a" (vm86.regs.eax), ++ "d" (vm86.regs.edx)); ++ } ++ i++; ++ goto out; ++ default: ++ printk(KERN_ERR "vesafb: BUG, opcode 0x%x emulation " ++ "not supported (EIP: 0x%lx)\n", ++ instr[i], (u32)(vm86.regs.cs << 4) + ++ vm86.regs.eip); ++ ret = 1; ++ goto out; ++ } ++ } ++out: vm86.regs.eip += i; ++ return ret; ++} ++ ++void vesafb_do_vm86(struct vm86_regs *regs) ++{ ++ unsigned int ret; ++ u8 *retcode = (void*)RET_CODE_ADDR; ++ ++ memset(&vm86,0,sizeof(vm86)); ++ memcpy(&vm86.regs, regs, sizeof(struct vm86_regs)); ++ ++ /* The return code */ ++ retcode[0] = 0xcd; /* int opcode */ ++ retcode[1] = 0xff; /* int number (255) */ ++ ++ /* We use int 0xff to get back to protected mode */ ++ memset(&vm86.int_revectored, 0, sizeof(vm86.int_revectored)); ++ ((unsigned char *)&vm86.int_revectored)[0xff / 8] |= (1 << (0xff % 8)); ++ ++ /* ++ * We want to call int 0x10, so we set: ++ * CS = 0x42 = 0x10 * 4 + 2 ++ * IP = 0x40 = 0x10 * 4 ++ * and SS:ESP. It's up to the caller to set the rest of the registers. ++ */ ++ vm86.regs.eflags = DEFAULT_VM86_FLAGS; ++ vm86.regs.cs = *(unsigned short *)0x42; ++ vm86.regs.eip = *(unsigned short *)0x40; ++ vm86.regs.ss = (STACK_ADDR >> 4); ++ vm86.regs.esp = ((STACK_ADDR & 0x0000f) + STACK_SIZE); ++ ++ /* These will be fetched off the stack when we come to an iret in the ++ * int's 0x10 code. */ ++ VM86_PUSHW(DEFAULT_VM86_FLAGS); ++ VM86_PUSHW((RET_CODE_ADDR >> 4)); /* return code segment */ ++ VM86_PUSHW((RET_CODE_ADDR & 0x0000f)); /* return code offset */ ++ ++ while(1) { ++ ret = vm86old(&vm86); ++ ++ if (VM86_TYPE(ret) == VM86_INTx) { ++ int vint = VM86_ARG(ret); ++ ++ /* If exit from vm86 was caused by int 0xff, then ++ * we're done.. */ ++ if (vint == 0xff) ++ goto out; ++ ++ /* .. otherwise, we have to call the int handler ++ * manually */ ++ VM86_PUSHW(vm86.regs.eflags); ++ VM86_PUSHW(vm86.regs.cs); ++ VM86_PUSHW(vm86.regs.eip); ++ ++ vm86.regs.cs = *(u16 *)((vint << 2) + 2); ++ vm86.regs.eip = *(u16 *)(vint << 2); ++ vm86.regs.eflags &= ~(VIF_MASK | TF_MASK); ++ } else if (VM86_TYPE(ret) == VM86_UNKNOWN) { ++ if (vm86_do_unknown()) ++ goto out; ++ } else { ++ printk(KERN_ERR "vesafb: BUG, returned from " ++ "vm86 with %x (EIP: 0x%lx)\n", ++ ret, (u32)(vm86.regs.cs << 4) + ++ vm86.regs.eip); ++ goto out; ++ } ++ } ++ ++out: /* copy the registers' state back to the caller's struct */ ++ memcpy(regs, &vm86.regs, sizeof(struct vm86_regs)); ++} ++ ++static int vesafb_remap_pfn_range(unsigned long start, unsigned long end, ++ unsigned long pgoff, unsigned long prot, ++ int type) ++{ ++ struct vm_area_struct *vma; ++ struct mm_struct *mm = current->mm; ++ int ret = 0; ++ ++ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); ++ if (!vma) ++ return -ENOMEM; ++ memset(vma, 0, sizeof(*vma)); ++ down_write(&mm->mmap_sem); ++ vma->vm_mm = mm; ++ vma->vm_start = start; ++ vma->vm_end = end; ++ vma->vm_flags = VM_READ | VM_WRITE | VM_EXEC; ++ vma->vm_flags |= mm->def_flags; ++ vma->vm_page_prot.pgprot = prot; ++ vma->vm_pgoff = pgoff; ++ ++ if ((ret = insert_vm_struct(mm, vma))) { ++ up_write(&mm->mmap_sem); ++ kmem_cache_free(vm_area_cachep, vma); ++ return ret; ++ } ++ ++ if (type) { ++ ret = zeromap_page_range(vma, ++ vma->vm_start, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot); ++ } else { ++ vma->vm_flags |= VM_SHARED; ++ ret = remap_pfn_range(vma, ++ vma->vm_start, ++ vma->vm_pgoff, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot); ++ } ++ up_write(&mm->mmap_sem); ++ return ret; ++} ++ ++static inline int vesafb_init_mem(void) ++{ ++ int ret = 0; ++ ++ /* The memory chunks we're remapping here should be multiples ++ * of PAGE_SIZE. */ ++ ret += vesafb_remap_pfn_range(0x00000, IVTBDA_SIZE, 0, ++ PROT_READ | PROT_EXEC | PROT_WRITE, 0); ++ ret += vesafb_remap_pfn_range(IVTBDA_SIZE, REAL_MEM_SIZE, 0, ++ PROT_READ | PROT_EXEC | PROT_WRITE, 1); ++ ret += vesafb_remap_pfn_range(0x9f000, 0x100000, ++ 0x9f000 >> PAGE_SHIFT, ++ PROT_READ | PROT_EXEC | PROT_WRITE, 0); ++ if (ret) ++ printk(KERN_ERR "vesafb thread: memory remapping failed\n"); ++ ++ return ret; ++} ++ ++#define vesafb_get_string(str) \ ++{ \ ++ /* The address is in the form ssssoooo, where oooo = offset, \ ++ * ssss = segment */ \ ++ addr = ((p_vbe(tsk->buf)->str & 0xffff0000) >> 12) + \ ++ (p_vbe(tsk->buf)->str & 0x0000ffff); \ ++ \ ++ /* The data is in ROM which is shared between processes, so we \ ++ * just translate the real mode address into one visible from \ ++ * kernel space */ \ ++ if (addr >= 0xa0000) { \ ++ p_vbe(tsk->buf)->str = (u32) __va(addr); \ ++ \ ++ /* The data is in the buffer, we just have to convert the \ ++ * address so that it points into the buffer user provided. */ \ ++ } else if (addr > BUF_ADDR && addr < BUF_ADDR + \ ++ sizeof(struct vesafb_vbe_ib)) { \ ++ addr -= BUF_ADDR; \ ++ p_vbe(tsk->buf)->str = (u32) (tsk->buf + addr); \ ++ \ ++ /* This should never happen: someone was insane enough to put \ ++ * the data somewhere in RAM.. */ \ ++ } else { |
