vgavesa.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * vga driver using just vesa bios to set up.
  11. *
  12. * note that setting hwaccel to zero will cause cursor ghosts to be
  13. * left behind. hwaccel set non-zero repairs this.
  14. */
  15. /* ensure an error here if there is a problem. */
  16. #include "u.h"
  17. #include "../port/lib.h"
  18. #include "mem.h"
  19. #include "dat.h"
  20. #include "fns.h"
  21. #include "io.h"
  22. #include "../port/error.h"
  23. #include "../../386/include/ureg.h"
  24. #define Image IMAGE
  25. #include <draw.h>
  26. #include <memdraw.h>
  27. #include <cursor.h>
  28. #include "screen.h"
  29. enum {
  30. Usesoftscreen = 1,
  31. };
  32. static void *hardscreen;
  33. static uint8_t modebuf[0x1000];
  34. #define WORD(p) ((p)[0] | ((p)[1]<<8))
  35. #define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
  36. #define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8
  37. #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
  38. static uint8_t*
  39. vbesetup(Ureg *u, int ax)
  40. {
  41. // Yes, it's a PA, but it's a real mode PA, and 32 bits are fine.
  42. uint32_t pa;
  43. pa = PADDR(RMBUF);
  44. memset(modebuf, 0, sizeof modebuf);
  45. memset(u, 0, sizeof *u);
  46. u->ax = ax;
  47. u->es = (pa>>4)&0xF000;
  48. u->di = pa&0xFFFF;
  49. return modebuf;
  50. }
  51. static void
  52. vbecall(Ureg *u)
  53. {
  54. Proc *up = externup();
  55. Chan *creg, *cmem;
  56. uint32_t pa;
  57. cmem = namec("/dev/realmodemem", Aopen, ORDWR, 0);
  58. if(waserror()){
  59. cclose(cmem);
  60. nexterror();
  61. }
  62. creg = namec("/dev/realmode", Aopen, ORDWR, 0);
  63. if(waserror()){
  64. cclose(creg);
  65. nexterror();
  66. }
  67. pa = PADDR(RMBUF);
  68. cmem->dev->write(cmem, modebuf, sizeof modebuf, pa);
  69. u->trap = 0x10;
  70. print("vbecall: sizeof u is %d\n", sizeof *u);
  71. creg->dev->write(creg, u, sizeof *u, 0);
  72. creg->dev->read(creg, u, sizeof *u, 0);
  73. if((u->ax&0xFFFF) != 0x004F)
  74. error("vesa bios error");
  75. cmem->dev->read(cmem, modebuf, sizeof modebuf, pa);
  76. poperror();
  77. cclose(creg);
  78. poperror();
  79. cclose(cmem);
  80. }
  81. static void
  82. vbecheck(void)
  83. {
  84. Ureg u;
  85. uint8_t *p;
  86. p = vbesetup(&u, 0x4F00);
  87. strcpy((char*)p, "VBE2");
  88. vbecall(&u);
  89. if(memcmp((char*)p, "VESA", 4) != 0)
  90. error("bad vesa signature");
  91. if(p[5] < 2)
  92. error("bad vesa version");
  93. }
  94. static int
  95. vbegetmode(void)
  96. {
  97. Ureg u;
  98. vbesetup(&u, 0x4F03);
  99. vbecall(&u);
  100. return u.bx;
  101. }
  102. static uint8_t*
  103. vbemodeinfo(int mode)
  104. {
  105. uint8_t *p;
  106. Ureg u;
  107. p = vbesetup(&u, 0x4F01);
  108. u.cx = mode;
  109. vbecall(&u);
  110. return p;
  111. }
  112. static void
  113. vesalinear(VGAscr *scr, int _1, int _2)
  114. {
  115. int i, mode, size, havesize;
  116. uint8_t *p;
  117. uint32_t paddr;
  118. Pcidev *pci;
  119. if(hardscreen) {
  120. scr->vaddr = 0;
  121. scr->paddr = scr->apsize = 0;
  122. return;
  123. }
  124. vbecheck();
  125. mode = vbegetmode();
  126. /*
  127. * bochs loses the top bits - cannot use this
  128. if((mode&(1<<14)) == 0)
  129. error("not in linear graphics mode");
  130. */
  131. mode &= 0x3FFF;
  132. p = vbemodeinfo(mode);
  133. if(!(WORD(p+0) & (1<<4)))
  134. error("not in VESA graphics mode");
  135. if(!(WORD(p+0) & (1<<7)))
  136. error("not in linear graphics mode");
  137. paddr = LONG(p+40);
  138. size = WORD(p+20)*WORD(p+16);
  139. size = ROUNDUP(size, PGSZ);
  140. /*
  141. * figure out max size of memory so that we have
  142. * enough if the screen is resized.
  143. */
  144. pci = nil;
  145. havesize = 0;
  146. while(!havesize && (pci = pcimatch(pci, 0, 0)) != nil){
  147. if(pci->ccrb != Pcibcdisp)
  148. continue;
  149. for(i=0; i<nelem(pci->mem); i++)
  150. if(paddr == (pci->mem[i].bar&~0x0F)){
  151. if(pci->mem[i].size > size)
  152. size = pci->mem[i].size;
  153. havesize = 1;
  154. break;
  155. }
  156. }
  157. /* no pci - heuristic guess */
  158. if(!havesize){
  159. if(size < 4*1024*1024)
  160. size = 4*1024*1024;
  161. else
  162. size = ROUND(size, 1024*1024);
  163. }
  164. if(size > 16*1024*1024) /* arbitrary */
  165. size = 16*1024*1024;
  166. vgalinearaddr(scr, paddr, size);
  167. if(scr->apsize)
  168. addvgaseg("vesascreen", scr->paddr, scr->apsize);
  169. if(Usesoftscreen){
  170. hardscreen = scr->vaddr;
  171. scr->vaddr = 0;
  172. scr->paddr = scr->apsize = 0;
  173. }
  174. }
  175. static void
  176. vesaflush(VGAscr *scr, Rectangle r)
  177. {
  178. int t, w, wid, off;
  179. uint32_t *hp, *sp, *esp;
  180. if(hardscreen == nil)
  181. return;
  182. if(rectclip(&r, scr->gscreen->r) == 0)
  183. return;
  184. sp = (uint32_t*)(scr->gscreendata->bdata + scr->gscreen->zero);
  185. t = (r.max.x * scr->gscreen->depth + 2*BI2WD-1) / BI2WD;
  186. w = (r.min.x * scr->gscreen->depth) / BI2WD;
  187. w = (t - w) * BY2WD;
  188. wid = scr->gscreen->width;
  189. off = r.min.y * wid + (r.min.x * scr->gscreen->depth) / BI2WD;
  190. hp = hardscreen;
  191. hp += off;
  192. sp += off;
  193. esp = sp + Dy(r) * wid;
  194. while(sp < esp){
  195. memmove(hp, sp, w);
  196. hp += wid;
  197. sp += wid;
  198. }
  199. }
  200. VGAdev vgavesadev = {
  201. "vesa",
  202. 0,
  203. 0,
  204. 0,
  205. vesalinear,
  206. 0,
  207. 0,
  208. 0,
  209. 0,
  210. vesaflush,
  211. };