github.com/icexin/eggos@v0.4.2-0.20220216025428-78b167e4f349/drivers/cga/backend.go (about)

     1  package cga
     2  
     3  import (
     4  	"unsafe"
     5  
     6  	"github.com/icexin/eggos/drivers/cga/fbcga"
     7  	"github.com/icexin/eggos/drivers/vbe"
     8  	"github.com/icexin/eggos/kernel/sys"
     9  )
    10  
    11  type Backend interface {
    12  	GetPos() int
    13  	SetPos(pos int)
    14  	// WritePos write char at given pos but not update pos
    15  	WritePos(pos int, char byte)
    16  	// WriteByte write char and advance pos
    17  	WriteByte(ch byte)
    18  }
    19  
    20  const (
    21  	CRTPORT = 0x3d4
    22  	bs      = '\b'
    23  	del     = 0x7f
    24  )
    25  
    26  var (
    27  	crt = (*[25 * 80]uint16)(unsafe.Pointer(uintptr(0xb8000)))
    28  )
    29  
    30  type cgabackend struct {
    31  }
    32  
    33  func (c *cgabackend) SetPos(pos int) {
    34  	sys.Outb(CRTPORT, 14)
    35  	sys.Outb(CRTPORT+1, byte(pos>>8))
    36  	sys.Outb(CRTPORT, 15)
    37  	sys.Outb(CRTPORT+1, byte(pos))
    38  }
    39  
    40  func (c *cgabackend) GetPos() int {
    41  	var pos int
    42  
    43  	// Cursor position: col + 80*row.
    44  	sys.Outb(CRTPORT, 14)
    45  	pos = int(sys.Inb(CRTPORT+1)) << 8
    46  	sys.Outb(CRTPORT, 15)
    47  	pos |= int(sys.Inb(CRTPORT + 1))
    48  	return pos
    49  }
    50  
    51  func (c *cgabackend) WritePos(pos int, ch byte) {
    52  	crt[pos] = uint16(ch) | 0x0700
    53  }
    54  
    55  func (c *cgabackend) WriteByte(ch byte) {
    56  	var pos int
    57  
    58  	// Cursor position: col + 80*row.
    59  	sys.Outb(CRTPORT, 14)
    60  	pos = int(sys.Inb(CRTPORT+1)) << 8
    61  	sys.Outb(CRTPORT, 15)
    62  	pos |= int(sys.Inb(CRTPORT + 1))
    63  
    64  	switch ch {
    65  	case '\n':
    66  		pos += 80 - pos%80
    67  	case bs, del:
    68  		if pos > 0 {
    69  			pos--
    70  		}
    71  	default:
    72  		// black on white
    73  		crt[pos] = uint16(ch&0xff) | 0x0700
    74  		pos++
    75  	}
    76  
    77  	// Scroll up
    78  	if pos/80 >= 25 {
    79  		copy(crt[:], crt[80:25*80])
    80  		pos -= 80
    81  		s := crt[pos : 25*80]
    82  		for i := range s {
    83  			// 在mac下开启qemu的-M accel=hvf,在滚屏的时候会出现`failed to decode instruction f 7f`
    84  			// 猜测是memclrNoHeapPointer造成的,具体原因未知
    85  			if false {
    86  			}
    87  			s[i] = 0
    88  		}
    89  	}
    90  	c.SetPos(pos)
    91  	crt[pos] = ' ' | 0x0700
    92  }
    93  
    94  func getbackend() Backend {
    95  	if vbe.IsEnable() {
    96  		return &fbcga.Backend
    97  	}
    98  	return &backend
    99  }