realmode.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #include "u.h"
  2. #include "tos.h"
  3. #include "../port/lib.h"
  4. #include "mem.h"
  5. #include "dat.h"
  6. #include "fns.h"
  7. #include "io.h"
  8. #include "ureg.h"
  9. #include "../port/error.h"
  10. /*
  11. * Back the processor into real mode to run a BIOS call,
  12. * then return. This must be used carefully, since it
  13. * completely disables hardware interrupts (e.g., the i8259)
  14. * while running. It is *not* using VM86 mode.
  15. * Maybe that's really the right answer, but real mode
  16. * is fine for now. We don't expect to use this very much --
  17. * just for VGA and APM.
  18. */
  19. #define realmoderegs (*(Ureg*)RMUADDR)
  20. #define LORMBUF (RMBUF-KZERO)
  21. static Ureg rmu;
  22. static Lock rmlock;
  23. void
  24. realmode(Ureg *ureg)
  25. {
  26. int s;
  27. ulong cr3;
  28. extern void realmode0(void); /* in l.s */
  29. extern void i8259off(void), i8259on(void);
  30. if(getconf("*norealmode"))
  31. return;
  32. lock(&rmlock);
  33. realmoderegs = *ureg;
  34. /* copy l.s so that it can be run from 16-bit mode */
  35. memmove((void*)RMCODE, (void*)KTZERO, 0x1000);
  36. s = splhi();
  37. m->pdb[PDX(0)] = m->pdb[PDX(KZERO)]; /* identity map low */
  38. cr3 = getcr3();
  39. putcr3(PADDR(m->pdb));
  40. i8259off();
  41. realmode0();
  42. if(m->tss){
  43. /*
  44. * Called from memory.c before initialization of mmu.
  45. * Don't turn interrupts on before the kernel is ready!
  46. */
  47. i8259on();
  48. }
  49. m->pdb[PDX(0)] = 0; /* remove low mapping */
  50. putcr3(cr3);
  51. splx(s);
  52. *ureg = realmoderegs;
  53. unlock(&rmlock);
  54. }
  55. static long
  56. rtrapread(Chan*, void *a, long n, vlong off)
  57. {
  58. if(off < 0)
  59. error("badarg");
  60. if(n+off > sizeof rmu)
  61. n = sizeof rmu - off;
  62. if(n <= 0)
  63. return 0;
  64. memmove(a, (char*)&rmu+off, n);
  65. return n;
  66. }
  67. static long
  68. rtrapwrite(Chan*, void *a, long n, vlong off)
  69. {
  70. if(off || n != sizeof rmu)
  71. error("write a Ureg");
  72. memmove(&rmu, a, sizeof rmu);
  73. /*
  74. * Sanity check
  75. */
  76. if(rmu.trap == 0x10){ /* VBE */
  77. rmu.es = (LORMBUF>>4)&0xF000;
  78. rmu.di = LORMBUF&0xFFFF;
  79. }else
  80. error("invalid trap arguments");
  81. realmode(&rmu);
  82. return n;
  83. }
  84. static long
  85. rmemrw(int isr, void *a, long n, vlong off)
  86. {
  87. if(off >= 1024*1024 || off+n >= 1024*1024)
  88. return 0;
  89. if(off < 0 || n < 0)
  90. error("bad offset/count");
  91. if(isr)
  92. memmove(a, KADDR((ulong)off), n);
  93. else{
  94. /* writes are more restricted */
  95. if(LORMBUF <= off && off < LORMBUF+BY2PG
  96. && off+n <= LORMBUF+BY2PG)
  97. {}
  98. else
  99. error("bad offset/count in write");
  100. memmove(KADDR((ulong)off), a, n);
  101. }
  102. return n;
  103. }
  104. static long
  105. rmemread(Chan*, void *a, long n, vlong off)
  106. {
  107. return rmemrw(1, a, n, off);
  108. }
  109. static long
  110. rmemwrite(Chan*, void *a, long n, vlong off)
  111. {
  112. return rmemrw(0, a, n, off);
  113. }
  114. void
  115. realmodelink(void)
  116. {
  117. addarchfile("realmode", 0660, rtrapread, rtrapwrite);
  118. addarchfile("realmodemem", 0660, rmemread, rmemwrite);
  119. }