realmode.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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. extern void realmode0(void); /* in l.s */
  28. extern void i8259off(void), i8259on(void);
  29. if(getconf("*norealmode"))
  30. return;
  31. lock(&rmlock);
  32. realmoderegs = *ureg;
  33. /* copy l.s so that it can be run from 16-bit mode */
  34. memmove((void*)RMCODE, (void*)KTZERO, 0x1000);
  35. s = splhi();
  36. m->pdb[PDX(0)] = m->pdb[PDX(KZERO)]; /* identity map low */
  37. putcr3(PADDR(m->pdb));
  38. i8259off();
  39. realmode0();
  40. if(m->tss){
  41. /*
  42. * Called from memory.c before initialization of mmu.
  43. * Don't turn interrupts on before the kernel is ready!
  44. */
  45. i8259on();
  46. putcr3(m->tss->cr3);
  47. }
  48. m->pdb[PDX(0)] = 0; /* remove low mapping */
  49. splx(s);
  50. *ureg = realmoderegs;
  51. unlock(&rmlock);
  52. }
  53. static long
  54. rtrapread(Chan*, void *a, long n, vlong off)
  55. {
  56. if(off < 0)
  57. error("badarg");
  58. if(n+off > sizeof rmu)
  59. n = sizeof rmu - off;
  60. if(n <= 0)
  61. return 0;
  62. memmove(a, (char*)&rmu+off, n);
  63. return n;
  64. }
  65. static long
  66. rtrapwrite(Chan*, void *a, long n, vlong off)
  67. {
  68. if(off || n != sizeof rmu)
  69. error("write a Ureg");
  70. memmove(&rmu, a, sizeof rmu);
  71. /*
  72. * Sanity check
  73. */
  74. if(rmu.trap == 0x10){ /* VBE */
  75. rmu.es = (LORMBUF>>4)&0xF000;
  76. rmu.di = LORMBUF&0xFFFF;
  77. }else
  78. error("invalid trap arguments");
  79. realmode(&rmu);
  80. return n;
  81. }
  82. static long
  83. rmemrw(int isr, void *a, long n, vlong off)
  84. {
  85. if(off >= 1024*1024 || off+n >= 1024*1024)
  86. return 0;
  87. if(off < 0 || n < 0)
  88. error("bad offset/count");
  89. if(isr)
  90. memmove(a, KADDR((ulong)off), n);
  91. else{
  92. /* writes are more restricted */
  93. if(LORMBUF <= off && off < LORMBUF+BY2PG
  94. && off+n <= LORMBUF+BY2PG)
  95. {}
  96. else
  97. error("bad offset/count in write");
  98. memmove(KADDR((ulong)off), a, n);
  99. }
  100. return n;
  101. }
  102. static long
  103. rmemread(Chan*, void *a, long n, vlong off)
  104. {
  105. return rmemrw(1, a, n, off);
  106. }
  107. static long
  108. rmemwrite(Chan*, void *a, long n, vlong off)
  109. {
  110. return rmemrw(0, a, n, off);
  111. }
  112. void
  113. realmodelink(void)
  114. {
  115. addarchfile("realmode", 0660, rtrapread, rtrapwrite);
  116. addarchfile("realmodemem", 0660, rmemread, rmemwrite);
  117. }