segment.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-08-06 JasonHu first version
  9. */
  10. #include "segment.h"
  11. #include "tss.h"
  12. #include "cpuport.h"
  13. #include <i386.h>
  14. #include <rtthread.h>
  15. struct rt_hw_segment
  16. {
  17. rt_uint16_t limit_low, base_low;
  18. rt_uint8_t base_mid, access_right;
  19. rt_uint8_t limit_high, base_high;
  20. };
  21. typedef struct rt_hw_segment rt_hw_segment_t;
  22. static void segment_set(rt_hw_segment_t *seg, rt_ubase_t limit,
  23. rt_ubase_t base, rt_ubase_t attributes)
  24. {
  25. seg->limit_low = limit & 0xffff;
  26. seg->base_low = base & 0xffff;
  27. seg->base_mid = (base >> 16) & 0xff;
  28. seg->access_right = attributes & 0xff;
  29. seg->limit_high = ((limit >> 16) & 0x0f) | ((attributes >> 8) & 0xf0);
  30. seg->base_high = (base >> 24) & 0xff;
  31. }
  32. /**
  33. * in x86, we can use fs/gs segment to save thread info,
  34. * set thread info base addr, os can use gs:0 to get the first
  35. * data on [base]
  36. */
  37. void rt_hw_seg_tls_set(rt_ubase_t base)
  38. {
  39. rt_hw_segment_t *seg = GDT_OFF2PTR(((rt_hw_segment_t *) GDT_VADDR), INDEX_USER_TLS);
  40. seg->base_low = base & 0xffff;
  41. seg->base_mid = (base >> 16) & 0xff;
  42. seg->base_high = (base >> 24) & 0xff;
  43. }
  44. rt_ubase_t rt_hw_seg_tls_get()
  45. {
  46. rt_hw_segment_t *seg = GDT_OFF2PTR(((rt_hw_segment_t *) GDT_VADDR), INDEX_USER_TLS);
  47. return (seg->base_low & 0xffff) | ((seg->base_mid & 0xff) << 16) | ((seg->base_high & 0xff) << 24);
  48. }
  49. void rt_hw_segment_init(void)
  50. {
  51. /* Global segment table */
  52. rt_hw_segment_t *gdt = (rt_hw_segment_t *) GDT_VADDR;
  53. int i;
  54. for (i = 0; i <= GDT_LIMIT/8; i++)
  55. {
  56. segment_set(GDT_OFF2PTR(gdt, i), 0, 0, 0);
  57. }
  58. segment_set(GDT_OFF2PTR(gdt, INDEX_KERNEL_CODE), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_KERNEL_CODE_ATTR);
  59. segment_set(GDT_OFF2PTR(gdt, INDEX_KERNEL_DATA), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_KERNEL_DATA_ATTR);
  60. rt_hw_tss_t *tss = rt_hw_tss_get();
  61. segment_set(GDT_OFF2PTR(gdt, INDEX_TSS), sizeof(rt_hw_tss_t) - 1, (rt_ubase_t )tss, GDT_TSS_ATTR);
  62. segment_set(GDT_OFF2PTR(gdt, INDEX_USER_CODE), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_USER_CODE_ATTR);
  63. segment_set(GDT_OFF2PTR(gdt, INDEX_USER_DATA), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_USER_DATA_ATTR);
  64. segment_set(GDT_OFF2PTR(gdt, INDEX_USER_TLS), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_USER_TLS_ATTR);
  65. extern void load_new_gdt(rt_ubase_t size, rt_ubase_t gdtr);
  66. load_new_gdt(GDT_LIMIT, GDT_VADDR);
  67. }