Deprecate VESA support.

This is in favor of bootloader-assisted mode switching. Grub has a
wonderful option we will exploit to set the video mode.

My laptop supports a couple of 32-bit video modes, which is nice,
because I'm not support 24-bit modes.

I'm not sure whether the super-sketchy video memory locator will work
in the real world, but we'll find out sometime soon.
This commit is contained in:
Kevin Lange 2012-09-17 22:22:25 -07:00
parent 8dec80deb9
commit 5ce042f2d8
9 changed files with 135 additions and 3110 deletions

View File

@ -181,38 +181,6 @@ ToAruOS contains additional software with the following copyright notices:
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
* The real-mode 8086 emulation provided for VESA support is distributed under the following license:
Copyright 2010 John Hodge (thePowersGang). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
official policies, either expressed or implied, of the author.
* As of January 23, 2012, the repository also contains the [DejaVu fonts](http://dejavu-fonts.org/wiki/Main_Page) package, which is a set of public-domain modifications of the Bitstream Vera font set, which is released under this license:
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream

View File

@ -297,7 +297,7 @@ extern int detect_cpu();
/* Video Drivers */
/* BOCHS / QEMU VBE Driver */
extern void graphics_install_bochs(uint16_t, uint16_t);
extern void graphics_install_vesa(uint16_t x, uint16_t y);
extern void graphics_install_preset(uint16_t, uint16_t);
extern void bochs_set_csr(int x, int y);
extern int bochs_get_csr_x();
extern int bochs_get_csr_y();

View File

@ -1,45 +0,0 @@
#ifndef VESA_H
#define VESA_H
#include <types.h>
typedef struct {
uint16_t Offset;
uint16_t Segment;
} t_farptr;
struct VesaControllerInfo {
char Signature[4]; // == "VBE2"
uint16_t Version; // == 0x0300 for Vesa 3.0
t_farptr OemString; // isa vbeFarPtr
uint8_t Capabilities[4];
t_farptr Videomodes; // isa vbeParPtr
uint16_t TotalMemory;// as # of 64KB blocks
};
struct VesaModeInfo {
uint16_t attributes;
uint8_t winA, winB;
uint16_t granularity;
uint16_t winsize;
uint16_t segmentA, segmentB;
t_farptr realFctPtr;
uint16_t pitch; // bytes per scanline
uint16_t Xres, Yres;
uint8_t Wchar, Ychar, planes, bpp, banks;
uint8_t memory_model, bank_size, image_pages;
uint8_t reserved0;
uint8_t red_mask, red_position;
uint8_t green_mask, green_position;
uint8_t blue_mask, blue_position;
uint8_t rsv_mask, rsv_position;
uint8_t directcolor_attributes;
uint32_t physbase; // your LFB address ;)
uint32_t reserved1;
uint16_t reserved2;
};
#endif

View File

@ -69,8 +69,8 @@ parse_args(
if (!strcmp(argp[1],"qemu")) {
/* Bochs / Qemu Video Device */
graphics_install_bochs(x,y);
} else if (!strcmp(argp[1],"vesa")) {
graphics_install_vesa(x,y);
} else if (!strcmp(argp[1],"preset")) {
graphics_install_preset(x,y);
} else {
kprintf("Unrecognized video adapter: %s\n", argp[1]);
}

View File

@ -1,25 +0,0 @@
Copyright 2010 John Hodge (thePowersGang). All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of the author.

File diff suppressed because it is too large Load Diff

View File

@ -1,329 +0,0 @@
/*
* Realmode Emulator Plugin
* - By John Hodge (thePowersGang)
*
* This code is published under the FreeBSD licence
* (See the file COPYING for details)
*
* ---
* Core Emulator Include
*/
#ifndef _RME_H_
#define _RME_H_
/**
* \file rme.h
* \brief Realmode Emulator Header
* \author John Hodge (thePowersGang)
*
* \section using Using RME
*
*/
/**
* \brief Enable the use of size overrides
* \note Disabling this will speed up emulation, but may cause undefined
* behavior with some BIOSes.
*
* If set to -1, size overrides will cause a \#UD
*/
#define USE_SIZE_OVERRIDES 0
/**
* \brief Size of a memory block
* \note Feel free to edit this value, just make sure it stays a power
* of two.
*/
#define RME_BLOCK_SIZE 0x1000
/**
* \brief Magic return Instruction Pointer
*/
#define RME_MAGIC_IP 0xFFFF
/**
* \brief Magic return Code Segment
*/
#define RME_MAGIC_CS 0xFFFF
/**
* \brief Error codes returned by ::RME_Call and ::RME_CallInt
*/
enum eRME_Errors
{
RME_ERR_OK, //!< Exited successfully
RME_ERR_INVAL, //!< Bad paramater passed to emulator
RME_ERR_BADMEM, //!< Emulator accessed invalid memory
RME_ERR_UNDEFOPCODE, //!< Undefined opcode
RME_ERR_DIVERR, //!< Divide error
RME_ERR_BUG, //!< Bug in the emulator
RME_ERR_LAST //!< Last Error
};
typedef union uGPR
{
#if USE_SIZE_OVERRIDES == 1
uint32_t D;
#endif
uint16_t W;
struct {
uint8_t L;
uint8_t H;
} B;
} tGPR;
/**
* \brief Emulator state structure
*/
typedef struct sRME_State
{
//! \brief General Purpose Registers
//! \{
tGPR AX, CX, DX, BX, SP, BP, SI, DI;
//! \}
//! \brief Segment Registers
//! \{
uint16_t SS; //!< Stack Segment
uint16_t DS; //!< Data Segment
uint16_t ES; //!< Extra Segment
//! \}
//! \brief Program Counter
//! \{
uint16_t CS; //!< Code Segment
uint16_t IP; //!< Instruction Pointer
//! \}
uint16_t Flags; //!< State Flags
/**
* \brief Emulator's Memory
*
* The ~1MiB realmode address space is broken into blocks of
* ::RME_BLOCK_SIZE bytes that can each point to different areas
* of memory.
* NOTE: There is no write protection on these blocks
* \note A value of NULL in a block indicates that the block is invalid
* \note 0x110000 bytes is all that is accessable using the realmode
* segmentation scheme (true max is 0xFFFF0+0xFFFF = 0x10FFEF)
*/
uint8_t *Memory[0x110000/RME_BLOCK_SIZE]; // 1Mib,64KiB in 256 4 KiB blocks
/**
* \brief High-Level Emulation Callback
* \param State Emulation state at the interrupt
* \param IntNum Interrupt number
* \return 1 if the call was handled, 0 if it should be emulated
*
* Called on all in-emulator INT calls
*/
int (*HLECallbacks[256])(struct sRME_State *State, int IntNum);
int InstrNum; //!< Total executed instructions
// --- Decoder State ---
/**
* \brief Decoder State
* \note Should not be touched except by the emulator
*/
struct {
int OverrideSegment;
int bOverrideOperand;
int bOverrideAddress;
int IPOffset;
} Decoder;
} tRME_State;
/**
* \brief Creates a blank RME instance
*/
extern tRME_State *RME_CreateState(void);
/**
* \brief Calls an interrupt
* \param State State returned from ::RME_CreateState
* \param Num Interrupt number
*/
extern int RME_CallInt(tRME_State *State, int Num);
/**
* \brief Executes the emulator until RME_MAGIC_CS:RME_MAGIC_IP is reached
* \param State State returned from ::RME_CreateState
*/
extern int RME_Call(tRME_State *State);
/**
* \brief Prints contents of the state's registers to debug
* \param State State returned from ::RME_CreateState
*/
extern void RME_DumpRegs(tRME_State *State);
/*
* Definitions specific to the internals of the emulator
*/
#ifdef _RME_C_
/**
*/
enum gpRegs
{
AL, CL, DL, BL,
AH, CH, DH, BH
};
enum sRegs
{
SREG_ES,
SREG_CS,
SREG_SS,
SREG_DS
};
#define OPCODE_RI(name, code) name##_RI_AL = code|AL, name##_RI_BL = code|BL,\
name##_RI_CL = code|CL, name##_RI_DL = code|DL,\
name##_RI_AH = code|AH, name##_RI_BH = code|BH,\
name##_RI_CH = code|CH, name##_RI_DH = code|DH,\
name##_RI_AX = code|AL|8, name##_RI_BX = code|BL|8,\
name##_RI_CX = code|CL|8, name##_RI_DX = code|DL|8,\
name##_RI_SP = code|AH|8, name##_RI_BP = code|CH|8,\
name##_RI_SI = code|DH|8, name##_RI_DI = code|BH|8
enum opcodes {
ADD_MR = 0x00, ADD_MRX = 0x01,
ADD_RM = 0x02, ADD_RMX = 0x03,
ADD_AI = 0x04, ADD_AIX = 0x05,
OR_MR = 0x08, OR_MRX = 0x09,
OR_RM = 0x0A, OR_RMX = 0x0B,
OR_AI = 0x0C, OR_AIX = 0x0D,
AND_MR = 0x20, AND_MRX = 0x21,
AND_RM = 0x22, AND_RMX = 0x23,
AND_AI = 0x24, AND_AIX = 0x25,
SUB_MR = 0x28, SUB_MRX = 0x29,
SUB_RM = 0x2A, SUB_RMX = 0x2B,
SUB_AI = 0x2C, SUB_AIX = 0x2D,
XOR_MR = 0x30, XOR_MRX = 0x31,
XOR_RM = 0x32, XOR_RMX = 0x33,
XOR_AI = 0x34, XOR_AIX = 0x35,
CMP_MR = 0x38, CMP_MRX = 0x39,
CMP_RM = 0x3A, CMP_RMX = 0x3B,
CMP_AI = 0x3C, CMP_AIX = 0x3D,
DEC_A = 0x48|AL, DEC_B = 0x48|BL,
DEC_C = 0x48|CL, DEC_D = 0x48|DL,
DEC_Sp = 0x48|AH, DEC_Bp = 0x48|CH,
DEC_Si = 0x48|DH, DEC_Di = 0x48|BH,
INC_A = 0x40|AL, INC_B = 0x40|BL,
INC_C = 0x40|CL, INC_D = 0x40|DL,
INC_Sp = 0x40|AH, INC_Bp = 0x40|CH,
INC_Si = 0x40|DH, INC_Di = 0x40|BH,
DIV_R = 0xFA, DIV_RX = 0xFB,
DIV_M = 0xFA, DIV_MX = 0xFB,
INT3 = 0xCC, INT_I = 0xCD,
IRET = 0xCF,
MOV_MoA = 0xA2, MOV_MoAX = 0xA3,
MOV_AMo = 0xA0, MOV_AMoX = 0xA1,
OPCODE_RI(MOV, 0xB0),
MOV_MI = 0xC6, MOV_MIX = 0xC7,
MOV_MR = 0x88, MOV_MRX = 0x89,
MOV_RM = 0x8A, MOV_RMX = 0x8B,
MOV_RS = 0x8C, MOV_SR = 0x8E,
MOV_MS = 0x8C, MOV_SM = 0x8E,
MUL_R = 0xF6, MUL_RX = 0xF7,
MUL_M = 0xF6, MUL_MX = 0xF7,
NOP = 0x90,
XCHG_AA = 0x90, XCHG_AB = 0x90|BL,
XCHG_AC = 0x90|CL, XCHG_AD = 0x90|DL,
XCHG_ASp = 0x90|AH, XCHG_ABp = 0x90|CH,
XCHG_ASi = 0x90|DH, XCHG_ADi = 0x90|BH,
XCHG_RM = 0x86,
NOT_R = 0xF6, NOT_RX = 0xF7,
NOT_M = 0xF6, NOT_MX = 0xF7,
IN_AI = 0xE4, IN_AIX = 0xE5,
IN_ADx = 0xEC, IN_ADxX = 0xED,
OUT_IA = 0xE6, OUT_IAX = 0xE7,
OUT_DxA = 0xEE, OUT_DxAX = 0xEF,
POP_AX = 0x58|AL, POP_BX = 0x58|BL,
POP_CX = 0x58|CL, POP_DX = 0x58|DL,
POP_SP = 0x58|AH, POP_BP = 0x58|CH,
POP_SI = 0x58|DH, POP_DI = 0x58|BH,
POP_ES = 7|(SREG_ES<<3),
POP_SS = 7|(SREG_SS<<3), POP_DS = 7|(SREG_DS<<3),
POP_MX = 0x8F,
POPA = 0x61, POPF = 0x9D,
PUSH_AX = 0x50|AL, PUSH_BX = 0x50|BL,
PUSH_CX = 0x50|CL, PUSH_DX = 0x50|DL,
PUSH_SP = 0x50|AH, PUSH_BP = 0x50|CH,
PUSH_SI = 0x50|DH, PUSH_DI = 0x50|BH,
// PUSH_MX = 0xFF, // - TODO: Check (maybe 0x87)
PUSH_ES = 6|(SREG_ES<<3), PUSH_CS = 6|(SREG_CS<<3),
PUSH_SS = 6|(SREG_SS<<3), PUSH_DS = 6|(SREG_DS<<3),
PUSH_I8 = 0x6A, PUSH_I = 0x68,
PUSHA = 0x60, PUSHF = 0x9C,
RET_N = 0xC3, RET_iN = 0xC2,
RET_F = 0xCB, RET_iF = 0xCA,
CALL_MF = 0xFF, CALL_MN = 0xFF,
CALL_N = 0xE8, CALL_F = 0x9A,
CALL_R = 0xFF,
JMP_MF = 0xFF, JMP_N = 0xE9,
JMP_S = 0xEB, JMP_F = 0xEA,
LES = 0xC4,
LDS = 0xC5,
LEA = 0x8D,
CLC = 0xF8, STC = 0xF9,
CLI = 0xFA, STI = 0xFB,
CLD = 0xFC, STD = 0xFD,
TEST_RM = 0x84, TEST_RMX = 0x85,
TEST_AI = 0xA8, TEST_AIX = 0xA9,
MOVSB = 0xA4, MOVSW = 0xA5,
CMPSB = 0xA6, CMPSW = 0xA7,
STOSB = 0xAA, STOSW = 0xAB,
LODSB = 0xAC, LODSW = 0xAD,
SCASB = 0xAE, SCASW = 0xAF,
INSB = 0x6C, INSW = 0x6D,
OUTSB = 0x6E, OUTSW = 0x6F,
// --- Unimplementeds
FPU_ARITH = 0xDC,
// --- Overrides
OVR_ES = 0x26,
OVR_CS = 0x2E,
OVR_SS = 0x36,
OVR_DS = 0x3E,
REPNZ = 0xF2, REP = 0xF3,
LOOPNZ = 0xE0, LOOPZ = 0xE1,
LOOP = 0xE2
};
#endif
#endif

View File

@ -1,256 +0,0 @@
/* vim: tabstop=4 shiftwidth=4 noexpandtab
*
* Bochs VBE / QEMU vga=std Graphics Driver
*/
#include <system.h>
#include <fs.h>
#include <types.h>
#include <vesa.h>
#include <logging.h>
#define PROMPT_FOR_MODE 0
/* Friggin' frick, this should be a config option
* because it's 4096 on some instances of Qemu,
* ie the one on my laptop, but it's 2048 on
* the EWS machines. */
#define BOCHS_BUFFER_SIZE 2048
#define PREFERRED_VY 4096
#define PREFERRED_B 32
uint16_t bochs_resolution_x = 0;
uint16_t bochs_resolution_y = 0;
uint16_t bochs_resolution_b = 0;
/*
* Address of the linear frame buffer.
* This can move, so it's a pointer instead of
* #define.
*/
uint8_t * bochs_vid_memory = (uint8_t *)0xE0000000;
uintptr_t current_scroll = 0;
void
bochs_set_y_offset(uint16_t y) {
outports(0x1CE, 0x9);
outports(0x1CF, y);
current_scroll = y;
}
uint16_t
bochs_current_scroll() {
return current_scroll;
}
uintptr_t
bochs_get_address() {
return (uintptr_t)bochs_vid_memory;
}
static void finalize_graphics(uint16_t x, uint16_t y, uint16_t b) {
bochs_resolution_x = x;
bochs_resolution_y = y;
bochs_resolution_b = b;
}
void
graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
blog("Setting up BOCHS/QEMU graphics controller...");
outports(0x1CE, 0x00);
uint16_t i = inports(0x1CF);
if (i < 0xB0C0 || i > 0xB0C6) {
return;
}
outports(0x1CF, 0xB0C4);
i = inports(0x1CF);
/* Disable VBE */
outports(0x1CE, 0x04);
outports(0x1CF, 0x00);
/* Set X resolution to 1024 */
outports(0x1CE, 0x01);
outports(0x1CF, resolution_x);
/* Set Y resolution to 768 */
outports(0x1CE, 0x02);
outports(0x1CF, resolution_y);
/* Set bpp to 32 */
outports(0x1CE, 0x03);
outports(0x1CF, PREFERRED_B);
/* Set Virtual Height to stuff */
outports(0x1CE, 0x07);
outports(0x1CF, PREFERRED_VY);
/* Re-enable VBE */
outports(0x1CE, 0x04);
outports(0x1CF, 0x41);
/* XXX: Massive hack */
uint32_t * text_vid_mem = (uint32_t *)0xA0000;
text_vid_mem[0] = 0xA5ADFACE;
for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) {
/* Enable the higher memory */
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
}
/* Go find it */
for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
bochs_vid_memory = (uint8_t *)x;
goto mem_found;
}
}
}
mem_found:
finalize_graphics(resolution_x, resolution_y, PREFERRED_B);
bfinish(0);
}
#include "../v8086/rme.h"
void
graphics_install_vesa(uint16_t x, uint16_t y) {
blog("Setting up VESA video controller...");
/* VESA Structs */
struct VesaControllerInfo *info = (void*)0x10000;
struct VesaModeInfo *modeinfo = (void*)0x9000;
/* 8086 Emulator Status */
tRME_State *emu;
void * lowCache;
lowCache = malloc(RME_BLOCK_SIZE);
memcpy(lowCache, NULL, RME_BLOCK_SIZE);
emu = RME_CreateState();
emu->Memory[0] = lowCache;
for (int i = RME_BLOCK_SIZE; i < 0x100000; i += RME_BLOCK_SIZE) {
emu->Memory[i/RME_BLOCK_SIZE] = (void*)i;
}
int ret, mode;
/* Find modes */
uint16_t * modes;
memcpy(info->Signature, "VBE2", 4);
emu->AX.W = 0x4F00;
emu->ES = 0x1000;
emu->DI.W = 0;
ret = RME_CallInt(emu, 0x10);
if (info->Version < 0x200 || info->Version > 0x300) {
bfinish(2);
kprintf("\033[JYou have attempted to use the VESA/VBE2 driver\nwith a card that does not support VBE2.\n");
kprintf("\nSystem responded to VBE request with version: 0x%x\n", info->Version);
STOP;
}
modes = (void*)FP_TO_LINEAR(info->Videomodes.Segment,info->Videomodes.Offset);
uint16_t best_x = 0;
uint16_t best_y = 0;
uint16_t best_b = 0;
uint16_t best_mode = 0;
for (int i = 1; modes[i] != 0xFFFF; ++i) {
emu->AX.W = 0x4F01;
emu->CX.W = modes[i];
emu->ES = 0x0900;
emu->DI.W = 0x0000;
RME_CallInt(emu, 0x10);
#if PROMPT_FOR_MODE
kprintf("%d = %dx%d:%d\n", i, modeinfo->Xres, modeinfo->Yres, modeinfo->bpp);
}
kprintf("Please select a mode: ");
char buf[10];
kgets(buf, 10);
mode = atoi(buf);
#else
if ((abs(modeinfo->Xres - x) < abs(best_x - x)) && (abs(modeinfo->Yres - y) < abs(best_y - y))) {
best_mode = i;
best_x = modeinfo->Xres;
best_y = modeinfo->Yres;
best_b = modeinfo->bpp;
}
}
for (int i = 1; modes[i] != 0xFFFF; ++i) {
emu->AX.W = 0x4F01;
emu->CX.W = modes[i];
emu->ES = 0x0900;
emu->DI.W = 0x0000;
RME_CallInt(emu, 0x10);
if (modeinfo->Xres == best_x && modeinfo->Yres == best_y) {
if (modeinfo->bpp > best_b) {
best_mode = i;
best_b = modeinfo->bpp;
}
}
}
if (best_b < 24) {
kprintf("!!! Rendering at this bit depth (%d) is not currently supported.\n", best_b);
STOP;
}
mode = best_mode;
#endif
emu->AX.W = 0x4F01;
if (mode < 100) {
emu->CX.W = modes[mode];
} else {
emu->CX.W = mode;
}
emu->ES = 0x0900;
emu->DI.W = 0x0000;
RME_CallInt(emu, 0x10);
emu->AX.W = 0x4F02;
emu->BX.W = modes[mode];
RME_CallInt(emu, 0x10);
uint16_t actual_x = modeinfo->Xres;
uint16_t actual_y = modeinfo->Yres;
uint16_t actual_b = modeinfo->bpp;
bochs_vid_memory = (uint8_t *)modeinfo->physbase;
if (!bochs_vid_memory) {
uint32_t * herp = (uint32_t *)0xA0000;
herp[0] = 0xA5ADFACE;
/* Enable the higher memory */
for (uintptr_t i = 0xE0000000; i <= 0xE0FF0000; i += 0x1000) {
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
}
for (uintptr_t i = 0xF0000000; i <= 0xF0FF0000; i += 0x1000) {
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
}
/* Go find it */
for (uintptr_t x = 0xE0000000; x < 0xE0FF0000; x += 0x1000) {
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
bochs_vid_memory = (uint8_t *)x;
goto mem_found;
}
}
for (uintptr_t x = 0xF0000000; x < 0xF0FF0000; x += 0x1000) {
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
bochs_vid_memory = (uint8_t *)x;
goto mem_found;
}
}
}
mem_found:
/*
* Finalize the graphics setup with the actual selected resolution.
*/
finalize_graphics(actual_x, actual_y, actual_b);
bfinish(0);
}

132
kernel/video/lfb.c Normal file
View File

@ -0,0 +1,132 @@
/* vim: tabstop=4 shiftwidth=4 noexpandtab
*
* Bochs VBE / QEMU vga=std Graphics Driver
*/
#include <system.h>
#include <fs.h>
#include <types.h>
#include <logging.h>
#define PREFERRED_VY 4096
#define PREFERRED_B 32
uint16_t bochs_resolution_x = 0;
uint16_t bochs_resolution_y = 0;
uint16_t bochs_resolution_b = 0;
/*
* Address of the linear frame buffer.
* This can move, so it's a pointer instead of
* #define.
*/
uint8_t * bochs_vid_memory = (uint8_t *)0xE0000000;
uintptr_t current_scroll = 0;
void
bochs_set_y_offset(uint16_t y) {
outports(0x1CE, 0x9);
outports(0x1CF, y);
current_scroll = y;
}
uint16_t
bochs_current_scroll() {
return current_scroll;
}
uintptr_t
bochs_get_address() {
return (uintptr_t)bochs_vid_memory;
}
static void finalize_graphics(uint16_t x, uint16_t y, uint16_t b) {
bochs_resolution_x = x;
bochs_resolution_y = y;
bochs_resolution_b = b;
}
void
graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
blog("Setting up BOCHS/QEMU graphics controller...");
outports(0x1CE, 0x00);
uint16_t i = inports(0x1CF);
if (i < 0xB0C0 || i > 0xB0C6) {
return;
}
outports(0x1CF, 0xB0C4);
i = inports(0x1CF);
/* Disable VBE */
outports(0x1CE, 0x04);
outports(0x1CF, 0x00);
/* Set X resolution to 1024 */
outports(0x1CE, 0x01);
outports(0x1CF, resolution_x);
/* Set Y resolution to 768 */
outports(0x1CE, 0x02);
outports(0x1CF, resolution_y);
/* Set bpp to 32 */
outports(0x1CE, 0x03);
outports(0x1CF, PREFERRED_B);
/* Set Virtual Height to stuff */
outports(0x1CE, 0x07);
outports(0x1CF, PREFERRED_VY);
/* Re-enable VBE */
outports(0x1CE, 0x04);
outports(0x1CF, 0x41);
/* XXX: Massive hack */
uint32_t * text_vid_mem = (uint32_t *)0xA0000;
text_vid_mem[0] = 0xA5ADFACE;
for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) {
/* Enable the higher memory */
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
}
/* Go find it */
for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
bochs_vid_memory = (uint8_t *)x;
goto mem_found;
}
}
}
mem_found:
finalize_graphics(resolution_x, resolution_y, PREFERRED_B);
bfinish(0);
}
void graphics_install_preset(uint16_t w, uint16_t h) {
blog("Graphics were pre-configured (thanks, bootloader!), locating video memory...");
uint16_t b = 32; /* If you are 24 bit, go away, we really do not support you. */
/* XXX: Massive hack */
uint32_t * herp = (uint32_t *)0xA0000;
herp[0] = 0xA5ADFACE;
for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) {
/* Enable the higher memory */
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
}
/* Go find it */
for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
bochs_vid_memory = (uint8_t *)x;
goto mem_found;
}
}
}
mem_found:
finalize_graphics(w,h,b);
bfinish(0);
}