虚拟机ubuntu,Ctrl+Alt+F1切换到图形模式,Ctrl+Alt+F6切换到命令行模式
framebuf在图形模式下无效,需要切换到命令行模式
vir2phy.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// 参考
// https://www.kernel.org/doc/Documentation/vm/pagemap.txt
#define page_map_file "/proc/self/pagemap"
#define PFN_MASK ((((uint64_t)1)<<55)-1)
#define PFN_PRESENT_FLAG (((uint64_t)1)<<63)
int mem_addr_vir2phy(unsigned long vir, unsigned long *phy)
{
int fd;
int page_size = getpagesize();
unsigned long vir_page_idx = vir / page_size;
unsigned long pfn_item_offset = vir_page_idx * sizeof(uint64_t);
uint64_t pfn_item;
fd = open(page_map_file, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "open %s failed", page_map_file);
return -1;
}
if ((off_t) - 1 == lseek(fd, pfn_item_offset, SEEK_SET))
{
fprintf(stderr, "lseek %s failed", page_map_file);
return -1;
}
if (sizeof(uint64_t) != read(fd, &pfn_item, sizeof(uint64_t)))
{
fprintf(stderr, "read %s failed", page_map_file);
return -1;
}
if (0 == (pfn_item & PFN_PRESENT_FLAG))
{
fprintf(stderr, "page is not present");
return -1;
}
*phy = (pfn_item & PFN_MASK) * page_size + vir % page_size;
return 0;
}
fbmap.h
/*
* fb矩阵输出
*/
#ifndef _FBMAP_H_
#define _FBMAP_H_
#include
//指定fb设备
#define FB_PATH "/dev/fb0"
//屏幕宽高(调用一次fb_output之后更新)
extern int fb_width, fb_height;
/*
* 屏幕输出
* data: 图像数组,数据长度必须为 width*height*3, RGB格式
* offsetX, offsetY: 屏幕起始位置
* width, height: 图像宽高
*/
void fb_output(uint8_t *data, uint32_t offsetX, uint32_t offsetY, uint32_t width, uint32_t height);
#endif
fbmap.c
/*
* fb矩阵输出
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "fbmap.h"
typedef struct
{
int fd;
unsigned char *fb;
size_t fbSize;
struct fb_var_screeninfo fbInfo;
//bytes per point
int bpp;
//bytes width, height
int bw, bh;
} FbMap;
static FbMap *fbmap = NULL;
int fb_width = 1024, fb_height = 600;
void fb_release(void)
{
if (!fbmap)
return;
if (fbmap->fb)
munmap(fbmap->fb, fbmap->fbSize);
if (fbmap->fd > 0)
close(fbmap->fd);
free(fbmap);
fbmap = NULL;
}
//返回0正常
int fb_init(void)
{
if (fbmap)
return 0;
fbmap = (FbMap *)calloc(1, sizeof(FbMap));
fbmap->fd = open(FB_PATH, O_RDWR);
if (fbmap->fd < 1)
{
fprintf(stderr, "fb_init: open %s err \r\n", FB_PATH);
fb_release();
return -1;
}
if (ioctl(fbmap->fd, FBIOGET_VSCREENINFO, &fbmap->fbInfo) < 0)
{
fprintf(stderr, "fb_init: ioctl FBIOGET_VSCREENINFO err \r\n");
fb_release();
return -1;
}
printf("frameBuffer: %s, %d x %d, %dbytes / %dbpp\r\n",
FB_PATH, fbmap->fbInfo.xres, fbmap->fbInfo.yres, fbmap->fbInfo.bits_per_pixel / 8, fbmap->fbInfo.bits_per_pixel);
fbmap->bpp = fbmap->fbInfo.bits_per_pixel / 8;
fbmap->bw = fbmap->bpp * fbmap->fbInfo.xres;
fbmap->bh = fbmap->bpp * fbmap->fbInfo.yres;
fbmap->fbSize = fbmap->fbInfo.xres * fbmap->fbInfo.yres * fbmap->bpp;
fb_width = fbmap->fbInfo.xres;
fb_height = fbmap->fbInfo.yres;
fbmap->fb = (unsigned char *)mmap(0, fbmap->fbSize, PROT_READ | PROT_WRITE, MAP_SHARED, fbmap->fd, 0);
if (!fbmap->fb)
{
fprintf(stderr, "fb_init: mmap size %ld err \r\n", fbmap->fbSize);
fb_release();
return -1;
}
int mem_addr_vir2phy(unsigned long vir, unsigned long *phy);
unsigned long phy;
*(fbmap->fb) = 0;
mem_addr_vir2phy((long)fbmap->fb, &phy);fprintf(stderr, "mmap vir:0x%lx, phy: 0x%lx \n", (long)fbmap->fb, (long)phy);
memset(fbmap->fb, 0, fbmap->fbSize);
return 0;
}
/*
* 屏幕输出
* data: 图像数组,数据长度必须为 width*height*3, RGB格式
* offsetX, offsetY: 屏幕起始位置
* width, height: 图像宽高
*/
void fb_output(uint8_t *data, uint32_t offsetX, uint32_t offsetY, uint32_t width, uint32_t height)
{
int x, y, offset;
//初始化检查
if (fb_init())
return;
//参数检查
if (!data || width < 1 || height < 1)
return;
//起始坐标限制
if (offsetX < 0)
offsetX = 0;
else if (offsetX >= fbmap->fbInfo.xres)
return;
if (offsetY < 0)
offsetY = 0;
else if (offsetY >= fbmap->fbInfo.yres)
return;
//范围限制
if (width < 1)
return;
else if (offsetX + width - 1 >= fbmap->fbInfo.xres)
width = fbmap->fbInfo.xres - offsetX;
if (height < 1)
return;
else if (offsetY + height - 1 >= fbmap->fbInfo.yres)
height = fbmap->fbInfo.yres - offsetY;
//覆盖画图
for (y = 0; y < height; y++)
{
//当前行在fb数据的偏移
offset = (y + offsetY) * fbmap->bw + (0 + offsetX) * fbmap->bpp;
//画data中的一行数据
for (x = 0; x < width; x++)
{
if (fbmap->bpp == 4)
fbmap->fb[offset + 3] = 0xFF; //A
fbmap->fb[offset + 2] = *data++; //R
fbmap->fb[offset + 1] = *data++; //G
fbmap->fb[offset + 0] = *data++; //B
offset += fbmap->bpp;
}
}
}
main.c
#include
#include
#include
#include "fbmap.h"
#define WIDTH 800
#define HEIGHT 600
// 设置颜色
void set(uint8_t *map, uint32_t mapSize, uint32_t rgbColor)
{
uint32_t offset;
uint8_t r = (rgbColor >> 16) & 0xFF;
uint8_t g = (rgbColor >> 8) & 0xFF;
uint8_t b = (rgbColor >> 0) & 0xFF;
for (offset = 0; offset < mapSize;)
{
map[offset++] = r;
map[offset++] = g;
map[offset++] = b;
}
}
int main(void)
{
uint8_t rgbMap[WIDTH * HEIGHT * 3];
while(1)
{
set(rgbMap, sizeof(rgbMap), 0xFF0000);//红
fb_output(rgbMap, 0, 0, WIDTH, HEIGHT);
sleep(1);
getchar();
set(rgbMap, sizeof(rgbMap), 0x00FF00);//绿
fb_output(rgbMap, 0, 0, WIDTH, HEIGHT);
sleep(1);
set(rgbMap, sizeof(rgbMap), 0x0000FF);//蓝
fb_output(rgbMap, 0, 0, WIDTH, HEIGHT);
sleep(1);
}
return 0;
}
编译:
gcc -o out main.c fbmap.c vir2phy.c
执行
sudo ./out
frameBuffer: /dev/fb0, 800 x 600, 4bytes / 32bpp
mmap vir:0x7efd54029000, phy: 0x3630b000
pagemap方式,ubuntu虚拟机可以获取到fb0物理地址(开机后framebuf对应的物理地址是固定不变的,但每次开机物理地址不一样),海思平台获取不到fb0物理地址?
海思HI3531DV200获取fb物理地址方式(ubuntu虚拟机获取不到):
struct fb_fix_screeninfo fb_fix;
if(ioctl(fbmap->fd, FBIOGET_FSCREENINFO, &fb_fix) < 0)
{
printf("ioctl FBIOGET_FSCREENINFO err\n");
return -1;
}
printf("fb phy addr:0x%0x\n", (int)fb_fix.smem_start);
fb phy addr:0x600e5000(每次开机地址固定)