QEMU의 Raspberry Pi2 모델에서 프레임 버퍼 그리기
17240 단어 RaspberryPiQEMUBaremetal
QEMU의 라즈베리 Pi2 모델은 VRAM의 주소만 알면 나체 금속도 간단하게 묘사할 수 있다.
사실 저는 라즈베리 파이 3 모델을 사용하고 싶은데 왜 움직이지 않는지 모르겠어요.(다시 한 번 시도해 봤는데 천 부분의 코드를 AARCH64로 바꿨어요. 라즈베리 Pi3 모델에서 Frabe Buffer도 움직였어요. 그런데 메일박스가 안 움직였어요.)
작업 예
QEMU는 2.12를 사용합니다.$ emu-system-arm -no-reboot -m 128 -M raspi3 -kernel kernel.elf
QEMU를 실행하면 표시되는 이미지입니다.
'30일이면 완성! OS 자체 제작 입문'의 예를 묘사했다.
설명
$ emu-system-arm -no-reboot -m 128 -M raspi3 -kernel kernel.elf
static Property bcm2835_fb_props[] = {
DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
DEFAULT_VCRAM_SIZE),
DEFINE_PROP_UINT32("xres", BCM2835FBState, xres, 640),
DEFINE_PROP_UINT32("yres", BCM2835FBState, yres, 480),
DEFINE_PROP_UINT32("bpp", BCM2835FBState, bpp, 16),
DEFINE_PROP_UINT32("pixo", BCM2835FBState, pixo, 1), /* 1=RGB, 0=BGR */
DEFINE_PROP_UINT32("alpha", BCM2835FBState, alpha, 2), /* alpha ignored */
DEFINE_PROP_END_OF_LIST()
};
uint16_t *vram = (uint16_t *) 0x4100000;
vram = 0xffff;
예시 동작의 코드를 그립니다.void boxfill8(uint16_t *vram, int xsize, uint16_t c, int x0, int y0, int x1, int y1)
{
int x, y;
for (y = y0; y <= y1; y++) {
for (x = x0; x <= x1; x++)
vram[y * xsize + x] = c;
}
return;
}
#define COL8_000000 (((0x00>>3)<<11) + ((0x00>>3)<<6) + (0x00>>3))
#define COL8_008484 (((0x00>>3)<<11) + ((0x84>>3)<<6) + (0x84>>3))
#define COL8_848484 (((0x84>>3)<<11) + ((0x84>>3)<<6) + (0x84>>3))
#define COL8_C6C6C6 (((0xC6>>3)<<11) + ((0xC6>>3)<<6) + (0xC6>>3))
#define COL8_FFFFFF (((0xFF>>3)<<11) + ((0xFF>>3)<<6) + (0xFF>>3))
void kernel_main(void)
{
uint16_t *vram = (uint16_t *) 0x4100000;
int x = 640 ,y = 480;
boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29);
boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28);
boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27);
boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1);
boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24);
boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4);
boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4);
boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5);
boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3);
boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3);
boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24);
boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4);
boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3);
boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3);
while (1)
;
}
VRAM 주소 취득
QEMU에서도 메일박스를 통해 VRAM 주소를 확인할 수 있습니다.
QEMU에서 아래 코드를 이동하여 0x4100000 주소를 얻었습니다.
메일박스의 사용 방법은 참고 페이지를 보십시오.
다만 실제 기기와 QEMU의 동작이 같은지는 잘 모르겠다.
실제 컴퓨터(Raspberry Pi)에서는 메일박스의 불빛을 통해 전달되는 주소에 0x40억 위안을 더했지만 QEMU라면 원래 주소가 아니면 이동할 수 없다.#define MB_READ 0x3F00B880
#define MB_WRITE 0x3F00B8A0
#define MB_STATUS 0x2000B898
void mb_write(uint32_t cmd_addr, uint32_t channel)
{
volatile uint32_t sta, cmd = 0;
do {
sta = *( (volatile uint32_t *) MB_STATUS);
} while (sta & 0x80000000);
cmd = cmd_addr | channel;
*((volatile uint32_t *) MB_WRITE) = cmd;
return;
}
void mb_read(uint32_t channel, uint32_t *resp_addr)
{
volatile uint32_t mail, sta;
do {
do {
sta = *( (volatile uint32_t *) MB_STATUS);
} while (sta & 0x40000000);
mail = *( (volatile uint32_t *) MB_READ);
} while ((mail & 0x0000000F) != channel);
*resp_addr = mail & 0xFFFFFFF0;
uart_puts("mb_read resp addr ");
uart_hex_puts(*resp_addr);
return;
}
static uint32_t pt[8192] __attribute__((aligned(16)));
uint16_t *fb_get_address(void)
{
uint32_t i;
uint32_t mail;
uint32_t *mailp;
pt[0] = 32; // buffer size in bytes
pt[1] = 0; // request code: process request
pt[2] = 0x40001; // tag: allocate frame buffer
pt[3] = 4; // length
pt[4] = 0;
pt[5] = 16; // alignments in bytes
pt[7] = 0; // end tag
uart_puts("mailbox cmd addr: ");
uart_hex_puts( (uint32_t) pt);
for(i=0; i<*((uint32_t *) pt)/4; i++) {
uart_hex_puts( *((uint32_t *) (pt+i)));
}
mb_write((uint32_t) pt, 8);
mb_read(8, &mail);
uart_puts("mailbox resp addr: ");
uart_hex_puts( (unsigned int) mail);
mailp = (uint32_t *) mail;
for(i=0; i<32/4; i++) {
uart_hex_puts( * (mailp+i));
}
return (uint16_t *) *(mailp + 5);
}
void kernel_main(void)
{
uint16_t *vram;
uart_init();
vram = fb_get_address();
...
}
위의 작업을 수행할 때 UART 출력 로그mailbox cmd addr: 0xB000
0x20
0x0
0x40001
0x4
0x0
0x10
0x0
0x0
mb_read resp addr 0xB000
mailbox resp addr: 0xB000
0x20
0x80000000
0x40001
0x4
0x80000008
0x4100000
0x96000
0x0
이 로그의 0x4100000은 VRAM 주소입니다.
QEMU의 메일박스 명령은 QEMU의 bcm2835_property.c 에 설명되어 있습니다.
참조 페이지
#define MB_READ 0x3F00B880
#define MB_WRITE 0x3F00B8A0
#define MB_STATUS 0x2000B898
void mb_write(uint32_t cmd_addr, uint32_t channel)
{
volatile uint32_t sta, cmd = 0;
do {
sta = *( (volatile uint32_t *) MB_STATUS);
} while (sta & 0x80000000);
cmd = cmd_addr | channel;
*((volatile uint32_t *) MB_WRITE) = cmd;
return;
}
void mb_read(uint32_t channel, uint32_t *resp_addr)
{
volatile uint32_t mail, sta;
do {
do {
sta = *( (volatile uint32_t *) MB_STATUS);
} while (sta & 0x40000000);
mail = *( (volatile uint32_t *) MB_READ);
} while ((mail & 0x0000000F) != channel);
*resp_addr = mail & 0xFFFFFFF0;
uart_puts("mb_read resp addr ");
uart_hex_puts(*resp_addr);
return;
}
static uint32_t pt[8192] __attribute__((aligned(16)));
uint16_t *fb_get_address(void)
{
uint32_t i;
uint32_t mail;
uint32_t *mailp;
pt[0] = 32; // buffer size in bytes
pt[1] = 0; // request code: process request
pt[2] = 0x40001; // tag: allocate frame buffer
pt[3] = 4; // length
pt[4] = 0;
pt[5] = 16; // alignments in bytes
pt[7] = 0; // end tag
uart_puts("mailbox cmd addr: ");
uart_hex_puts( (uint32_t) pt);
for(i=0; i<*((uint32_t *) pt)/4; i++) {
uart_hex_puts( *((uint32_t *) (pt+i)));
}
mb_write((uint32_t) pt, 8);
mb_read(8, &mail);
uart_puts("mailbox resp addr: ");
uart_hex_puts( (unsigned int) mail);
mailp = (uint32_t *) mail;
for(i=0; i<32/4; i++) {
uart_hex_puts( * (mailp+i));
}
return (uint16_t *) *(mailp + 5);
}
void kernel_main(void)
{
uint16_t *vram;
uart_init();
vram = fb_get_address();
...
}
mailbox cmd addr: 0xB000
0x20
0x0
0x40001
0x4
0x0
0x10
0x0
0x0
mb_read resp addr 0xB000
mailbox resp addr: 0xB000
0x20
0x80000000
0x40001
0x4
0x80000008
0x4100000
0x96000
0x0
RPiHaribote의mailbox.c
Reference
이 문제에 관하여(QEMU의 Raspberry Pi2 모델에서 프레임 버퍼 그리기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/eggman/items/2af2a0754f328d5f8328텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)