github.com/jspc/eggos@v0.5.1-0.20221028160421-556c75c878a5/kernel/seg_amd64.go (about)

     1  package kernel
     2  
     3  import (
     4  	"unsafe"
     5  
     6  	"github.com/jspc/eggos/kernel/sys"
     7  )
     8  
     9  const (
    10  	segDplKernel = 0x00
    11  	segDplUser   = 0x60
    12  )
    13  
    14  const (
    15  	_KCODE_IDX = 1
    16  	_KDATA_IDX = 2
    17  	_UCODE_IDX = 3
    18  	_UDATA_IDX = 4
    19  	_TSS_IDX   = 5
    20  )
    21  
    22  var (
    23  	gdt    [7]gdtSegDesc
    24  	gdtptr [10]byte
    25  
    26  	idt    [256]idtSetDesc
    27  	idtptr [10]byte
    28  
    29  	tss [26]uint32
    30  )
    31  
    32  type gdtSegDesc [8]byte
    33  
    34  type idtSetDesc struct {
    35  	Addr1    uint16
    36  	Selector uint16
    37  	Attr     uint16
    38  	Addr2    uint16
    39  	Addr3    uint32
    40  	Reserved uint32
    41  }
    42  
    43  //go:nosplit
    44  func lgdt(gdtptr uintptr)
    45  
    46  //go:nosplit
    47  func lidt(idtptr uintptr)
    48  
    49  //go:nosplit
    50  func ltr(sel uintptr)
    51  
    52  //go:nosplit
    53  func reloadCS()
    54  
    55  //go:nosplit
    56  func setGdtCodeDesc(desc *gdtSegDesc, dpl uint8) {
    57  	desc[5] |= dpl | 0x99 // P=1 C=0
    58  	desc[6] |= 0x20       // D=0 L=1
    59  }
    60  
    61  //go:nosplit
    62  func setGdtDataDesc(desc *gdtSegDesc, dpl uint8) {
    63  	desc[5] |= dpl | 0x92 // P=1 W=1
    64  }
    65  
    66  //go:nosplit
    67  func setTssDesc(lo, hi *gdtSegDesc, addr, limit uintptr) {
    68  	// tss limit 0-15
    69  	lo[0] = byte(limit)
    70  	lo[1] = byte(limit >> 8)
    71  	// tss base 0-15
    72  	lo[2] = byte(addr)
    73  	lo[3] = byte(addr >> 8)
    74  	// tss base 16-23
    75  	lo[4] = byte(addr >> 16)
    76  	// type 64 bit tss, P=1
    77  	lo[5] = 0x89
    78  	// limit 16-19 and AVL=1
    79  	lo[6] = 0x80 | byte(limit>>16)&0x07
    80  	// base addr 24-31 G=0
    81  	lo[7] = byte(addr >> 24)
    82  
    83  	// base addr 32-63
    84  	*(*uint32)(unsafe.Pointer(hi)) = uint32(addr >> 32)
    85  }
    86  
    87  //go:nosplit
    88  func gdtInit() {
    89  	// leave gdt[0] untouched
    90  	setGdtCodeDesc(&gdt[_KCODE_IDX], segDplKernel)
    91  	setGdtDataDesc(&gdt[_KDATA_IDX], segDplKernel)
    92  	setGdtCodeDesc(&gdt[_UCODE_IDX], segDplUser)
    93  	setGdtDataDesc(&gdt[_UDATA_IDX], segDplUser)
    94  	tssAddr := uintptr(unsafe.Pointer(&tss[0]))
    95  	tssLimit := uintptr(unsafe.Sizeof(tss)) - 1
    96  	setTssDesc(&gdt[_TSS_IDX], &gdt[_TSS_IDX+1], tssAddr, tssLimit)
    97  
    98  	limit := (*uint16)(unsafe.Pointer(&gdtptr[0]))
    99  	base := (*uint64)(unsafe.Pointer(&gdtptr[2]))
   100  	*limit = uint16(unsafe.Sizeof(gdt) - 1)
   101  	*base = uint64(uintptr(unsafe.Pointer(&gdt[0])))
   102  	lgdt(uintptr(unsafe.Pointer(&gdtptr[0])))
   103  	ltr(_TSS_IDX << 3)
   104  	reloadCS()
   105  }
   106  
   107  //go:nosplit
   108  func setIdtDesc(desc *idtSetDesc, addr uintptr, dpl byte) {
   109  	desc.Addr1 = uint16(addr & 0xffff)
   110  	desc.Selector = 8
   111  	desc.Attr = 0x8e00 | uint16(dpl)<<8 // P=1 TYPE=e interrupt gate
   112  	desc.Addr2 = uint16(addr >> 16 & 0xffff)
   113  	desc.Addr3 = uint32(addr>>32) & 0xffffffff
   114  }
   115  
   116  //go:nosplit
   117  func idtInit() {
   118  	for i := 0; i < 256; i++ {
   119  		setIdtDesc(&idt[i], sys.FuncPC(vectors[i]), segDplKernel)
   120  	}
   121  	setIdtDesc(&idt[0x80], sys.FuncPC(vectors[0x80]), segDplUser)
   122  
   123  	limit := (*uint16)(unsafe.Pointer(&idtptr[0]))
   124  	base := (*uint64)(unsafe.Pointer(&idtptr[2]))
   125  	*limit = uint16(unsafe.Sizeof(idt) - 1)
   126  	*base = uint64(uintptr(unsafe.Pointer(&idt[0])))
   127  	lidt(uintptr(unsafe.Pointer(&idtptr)))
   128  }
   129  
   130  //go:nosplit
   131  func setTssSP0(addr uintptr) {
   132  	tss[1] = uint32(addr)
   133  	tss[2] = uint32(addr >> 32)
   134  }