vgavesa.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * vga driver using just vesa bios to set up.
  3. *
  4. * note that setting hwaccel to zero will cause cursor ghosts to be
  5. * left behind. hwaccel set non-zero repairs this.
  6. */
  7. #include "u.h"
  8. #include "../port/lib.h"
  9. #include "mem.h"
  10. #include "dat.h"
  11. #include "fns.h"
  12. #include "io.h"
  13. #include "../port/error.h"
  14. #include "ureg.h"
  15. #define Image IMAGE
  16. #include <draw.h>
  17. #include <memdraw.h>
  18. #include <cursor.h>
  19. #include "screen.h"
  20. static void *hardscreen;
  21. #define WORD(p) ((p)[0] | ((p)[1]<<8))
  22. #define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
  23. #define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8
  24. #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
  25. extern void realmode(Ureg*);
  26. static uchar*
  27. vbesetup(Ureg *u, int ax)
  28. {
  29. ulong pa;
  30. pa = PADDR(RMBUF);
  31. memset(u, 0, sizeof *u);
  32. u->ax = ax;
  33. u->es = (pa>>4)&0xF000;
  34. u->di = pa&0xFFFF;
  35. return (void*)RMBUF;
  36. }
  37. static void
  38. vbecall(Ureg *u)
  39. {
  40. u->trap = 0x10;
  41. realmode(u);
  42. if((u->ax&0xFFFF) != 0x004F)
  43. error("vesa bios error");
  44. }
  45. static void
  46. vbecheck(void)
  47. {
  48. Ureg u;
  49. uchar *p;
  50. p = vbesetup(&u, 0x4F00);
  51. strcpy((char*)p, "VBE2");
  52. vbecall(&u);
  53. if(memcmp((char*)p, "VESA", 4) != 0)
  54. error("bad vesa signature");
  55. if(p[5] < 2)
  56. error("bad vesa version");
  57. }
  58. static int
  59. vbegetmode(void)
  60. {
  61. Ureg u;
  62. vbesetup(&u, 0x4F03);
  63. vbecall(&u);
  64. return u.bx;
  65. }
  66. static uchar*
  67. vbemodeinfo(int mode)
  68. {
  69. uchar *p;
  70. Ureg u;
  71. p = vbesetup(&u, 0x4F01);
  72. u.cx = mode;
  73. vbecall(&u);
  74. return p;
  75. }
  76. static void
  77. vesalinear(VGAscr *scr, int, int)
  78. {
  79. int i, mode, size;
  80. uchar *p;
  81. ulong paddr;
  82. Pcidev *pci;
  83. vbecheck();
  84. mode = vbegetmode();
  85. /* bochs loses the top bits - cannot use this
  86. if((mode&(1<<14)) == 0)
  87. error("not in linear graphics mode");
  88. */
  89. mode &= 0x3FFF;
  90. p = vbemodeinfo(mode);
  91. if(!(WORD(p+0) & (1<<4)))
  92. error("not in VESA graphics mode");
  93. if(!(WORD(p+0) & (1<<7)))
  94. error("not in linear graphics mode");
  95. paddr = LONG(p+40);
  96. size = WORD(p+20)*WORD(p+16);
  97. size = PGROUND(size);
  98. /*
  99. * figure out max size of memory so that we have
  100. * enough if the screen is resized.
  101. */
  102. pci = nil;
  103. while((pci = pcimatch(pci, 0, 0)) != nil){
  104. if(pci->ccrb != Pcibcdisp)
  105. continue;
  106. for(i=0; i<nelem(pci->mem); i++)
  107. if(paddr == (pci->mem[i].bar&~0x0F)){
  108. if(pci->mem[i].size > size)
  109. size = pci->mem[i].size;
  110. goto havesize;
  111. }
  112. }
  113. /* no pci - heuristic guess */
  114. if(size < 4*1024*1024)
  115. size = 4*1024*1024;
  116. else
  117. size = ROUND(size, 1024*1024);
  118. havesize:
  119. if(size > 16*1024*1024) /* probably arbitrary; could increase */
  120. size = 16*1024*1024;
  121. vgalinearaddr(scr, paddr, size);
  122. hardscreen = scr->vaddr;
  123. /* let mtrr harmlessly fail on old CPUs, e.g., P54C */
  124. if (!waserror()){
  125. mtrr(paddr, size, "wc");
  126. poperror();
  127. }
  128. }
  129. static void
  130. vesaflush(VGAscr *scr, Rectangle r)
  131. {
  132. int t, w, wid, off;
  133. ulong *hp, *sp, *esp;
  134. if(rectclip(&r, scr->gscreen->r) == 0)
  135. return;
  136. hp = hardscreen;
  137. assert(hp != nil);
  138. sp = (ulong*)(scr->gscreendata->bdata + scr->gscreen->zero);
  139. t = (r.max.x * scr->gscreen->depth + 2*BI2WD-1) / BI2WD;
  140. w = (r.min.x * scr->gscreen->depth) / BI2WD;
  141. w = (t - w) * BY2WD;
  142. wid = scr->gscreen->width;
  143. off = r.min.y * wid + (r.min.x * scr->gscreen->depth) / BI2WD;
  144. hp += off;
  145. sp += off;
  146. esp = sp + Dy(r) * wid;
  147. while(sp < esp){
  148. memmove(hp, sp, w);
  149. hp += wid;
  150. sp += wid;
  151. }
  152. }
  153. VGAdev vgavesadev = {
  154. "vesa",
  155. 0,
  156. 0,
  157. 0,
  158. vesalinear,
  159. 0,
  160. 0,
  161. 0,
  162. 0,
  163. vesaflush,
  164. };