2011-12-11 03:34:10 +04:00
|
|
|
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
|
|
|
*
|
|
|
|
* System Functions
|
|
|
|
*
|
|
|
|
* Part of the ToAru OS Kernel
|
|
|
|
* (C) 2011 Kevin Lange
|
|
|
|
* Released under the terms of the NCSA License, see the included
|
|
|
|
* README file for further information.
|
2011-03-29 04:34:44 +04:00
|
|
|
*/
|
2011-01-28 22:56:56 +03:00
|
|
|
#include <system.h>
|
|
|
|
|
2012-01-11 05:54:05 +04:00
|
|
|
unsigned int __irq_sem = 0;
|
2011-12-11 05:15:12 +04:00
|
|
|
|
|
|
|
void spin_lock(uint8_t volatile * lock) {
|
|
|
|
while(__sync_lock_test_and_set(lock, 0x01)) {
|
2012-02-01 05:27:38 +04:00
|
|
|
switch_task(1);
|
2011-12-11 05:15:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void spin_unlock(uint8_t volatile * lock) {
|
|
|
|
__sync_lock_release(lock);
|
|
|
|
}
|
|
|
|
|
2012-03-28 06:47:25 +04:00
|
|
|
char * boot_arg = NULL;
|
2012-09-02 13:24:25 +04:00
|
|
|
char * boot_arg_extra = NULL;
|
2012-03-28 06:47:25 +04:00
|
|
|
|
2011-01-28 22:56:56 +03:00
|
|
|
/*
|
|
|
|
* memcpy
|
|
|
|
* Copy from source to destination. Assumes that
|
|
|
|
* source and destination are not overlapping.
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
void * memcpy(void * restrict dest, const void * restrict src, size_t count) {
|
2011-10-31 10:17:26 +04:00
|
|
|
asm volatile ("cld; rep movsb" : "+c" (count), "+S" (src), "+D" (dest) :: "memory");
|
2011-01-28 22:56:56 +03:00
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
int max(int a, int b) {
|
2011-03-30 01:35:02 +04:00
|
|
|
return (a > b) ? a : b;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
int min(int a, int b) {
|
2011-12-27 05:23:58 +04:00
|
|
|
return (a > b) ? b : a;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
int abs(int a) {
|
2011-03-30 01:35:02 +04:00
|
|
|
return (a >= 0) ? a : -a;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
void swap(int *a, int *b) {
|
2011-03-30 01:35:02 +04:00
|
|
|
int t = *a;
|
|
|
|
*a = *b;
|
|
|
|
*b = t;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
void * memmove(void * restrict dest, const void * restrict src, size_t count) {
|
2011-03-29 04:34:44 +04:00
|
|
|
size_t i;
|
|
|
|
unsigned char *a = dest;
|
|
|
|
const unsigned char *b = src;
|
|
|
|
if (src < dest) {
|
|
|
|
for ( i = count; i > 0; --i) {
|
|
|
|
a[i-1] = b[i-1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( i = 0; i < count; ++i) {
|
|
|
|
a[i] = b[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
int strcmp(const char * a, const char * b) {
|
2011-01-29 23:12:00 +03:00
|
|
|
uint32_t i = 0;
|
|
|
|
while (1) {
|
|
|
|
if (a[i] < b[i]) {
|
|
|
|
return -1;
|
|
|
|
} else if (a[i] > b[i]) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
if (a[i] == '\0') {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-28 22:56:56 +03:00
|
|
|
/*
|
|
|
|
* memset
|
|
|
|
* Set `count` bytes to `val`.
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
void * memset(void * b, int val, size_t count) {
|
2011-10-31 10:17:26 +04:00
|
|
|
asm volatile ("cld; rep stosb" : "+c" (count), "+D" (b) : "a" (val) : "memory");
|
2011-01-28 22:56:56 +03:00
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* memsetw
|
|
|
|
* Set `count` shorts to `val`.
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
unsigned short * memsetw(unsigned short * dest, unsigned short val, int count) {
|
|
|
|
int i = 0;
|
2011-01-28 22:56:56 +03:00
|
|
|
for ( ; i < count; ++i ) {
|
|
|
|
dest[i] = val;
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* strlen
|
|
|
|
* Returns the length of a given `str`.
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
uint32_t strlen(const char *str) {
|
2011-01-28 22:56:56 +03:00
|
|
|
int i = 0;
|
|
|
|
while (str[i] != (char)0) {
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2012-12-01 06:26:47 +04:00
|
|
|
char * strdup(const char *str) {
|
|
|
|
int len = strlen(str);
|
|
|
|
char * out = malloc(sizeof(char) * (len+1));
|
|
|
|
memcpy(out, str, len+1);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
char * strcpy(char * dest, const char * src) {
|
|
|
|
int len = strlen(src);
|
|
|
|
memcpy(dest, src, len+1);
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2011-03-26 06:29:54 +03:00
|
|
|
uint32_t __attribute__ ((pure)) krand() {
|
|
|
|
static uint32_t x = 123456789;
|
|
|
|
static uint32_t y = 362436069;
|
|
|
|
static uint32_t z = 521288629;
|
|
|
|
static uint32_t w = 88675123;
|
|
|
|
|
|
|
|
uint32_t t;
|
|
|
|
|
|
|
|
t = x ^ (x << 11);
|
|
|
|
x = y; y = z; z = w;
|
|
|
|
return w = w ^ (w >> 19) ^ t ^ (t >> 8);
|
|
|
|
}
|
|
|
|
|
2011-02-11 06:45:29 +03:00
|
|
|
/*
|
|
|
|
* atoi
|
|
|
|
* Naïve implementation thereof.
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
int atoi(const char * str) {
|
2011-02-11 06:45:29 +03:00
|
|
|
uint32_t len = strlen(str);
|
|
|
|
uint32_t out = 0;
|
|
|
|
uint32_t i;
|
|
|
|
uint32_t pow = 1;
|
|
|
|
for (i = len; i > 0; --i) {
|
|
|
|
out += (str[i-1] - 48) * pow;
|
|
|
|
pow *= 10;
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
unsigned short inports(unsigned short _port) {
|
2011-03-26 06:29:54 +03:00
|
|
|
unsigned short rv;
|
2011-10-31 10:17:26 +04:00
|
|
|
asm volatile ("inw %1, %0" : "=a" (rv) : "dN" (_port));
|
2011-03-26 06:29:54 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
void outports(unsigned short _port, unsigned short _data) {
|
2011-10-31 10:17:26 +04:00
|
|
|
asm volatile ("outw %1, %0" : : "dN" (_port), "a" (_data));
|
2011-03-26 06:29:54 +03:00
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
unsigned int inportl(unsigned short _port) {
|
2011-03-29 04:34:44 +04:00
|
|
|
unsigned short rv;
|
2011-10-31 10:17:26 +04:00
|
|
|
asm volatile ("inl %%dx, %%eax" : "=a" (rv) : "dN" (_port));
|
2011-03-29 04:34:44 +04:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
void outportl(unsigned short _port, unsigned int _data) {
|
2011-10-31 10:17:26 +04:00
|
|
|
asm volatile ("outl %%eax, %%dx" : : "dN" (_port), "a" (_data));
|
2011-03-29 04:34:44 +04:00
|
|
|
}
|
|
|
|
|
2011-01-28 22:56:56 +03:00
|
|
|
/*
|
|
|
|
* inportb
|
|
|
|
* Read from an I/O port.
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
unsigned char inportb(unsigned short _port) {
|
2011-01-28 22:56:56 +03:00
|
|
|
unsigned char rv;
|
2011-10-31 10:17:26 +04:00
|
|
|
asm volatile ("inb %1, %0" : "=a" (rv) : "dN" (_port));
|
2011-01-28 22:56:56 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* outportb
|
|
|
|
* Write to an I/O port.
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
void outportb(unsigned short _port, unsigned char _data) {
|
2011-10-31 10:17:26 +04:00
|
|
|
asm volatile ("outb %1, %0" : : "dN" (_port), "a" (_data));
|
2011-01-28 22:56:56 +03:00
|
|
|
}
|
|
|
|
|
2011-12-13 10:48:04 +04:00
|
|
|
/*
|
|
|
|
* Output multiple sets of shorts
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
void outportsm(unsigned short port, unsigned char * data, unsigned long size) {
|
2011-12-13 10:48:04 +04:00
|
|
|
asm volatile ("rep outsw" : "+S" (data), "+c" (size) : "d" (port));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Input multiple sets of shorts
|
|
|
|
*/
|
2012-10-04 09:01:45 +04:00
|
|
|
void inportsm(unsigned short port, unsigned char * data, unsigned long size) {
|
2011-12-13 10:48:04 +04:00
|
|
|
asm volatile ("rep insw" : "+D" (data), "+c" (size) : "d" (port) : "memory");
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
char * strtok_r(char * str, const char * delim, char ** saveptr) {
|
2011-02-07 23:30:17 +03:00
|
|
|
char * token;
|
|
|
|
if (str == NULL) {
|
|
|
|
str = *saveptr;
|
|
|
|
}
|
|
|
|
str += strspn(str, delim);
|
|
|
|
if (*str == '\0') {
|
|
|
|
*saveptr = str;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
token = str;
|
|
|
|
str = strpbrk(token, delim);
|
|
|
|
if (str == NULL) {
|
|
|
|
*saveptr = (char *)lfind(token, '\0');
|
|
|
|
} else {
|
|
|
|
*str = '\0';
|
|
|
|
*saveptr = str + 1;
|
|
|
|
}
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
size_t lfind(const char * str, const char accept) {
|
2011-02-07 23:30:17 +03:00
|
|
|
size_t i = 0;
|
|
|
|
while ( str[i] != accept) {
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return (size_t)(str) + i;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
size_t rfind(const char * str, const char accept) {
|
2011-11-02 03:51:15 +04:00
|
|
|
size_t i = strlen(str) - 1;
|
|
|
|
while (str[i] != accept) {
|
|
|
|
if (i == 0) return UINT32_MAX;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
return (size_t)(str) + i;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
char * strstr(const char * haystack, const char * needle) {
|
2011-11-27 01:25:59 +04:00
|
|
|
const char * out = NULL;
|
|
|
|
const char * ptr;
|
|
|
|
const char * acc;
|
|
|
|
const char * p;
|
|
|
|
size_t s = strlen(needle);
|
|
|
|
for (ptr = haystack; *ptr != '\0'; ++ptr) {
|
|
|
|
size_t accept = 0;
|
|
|
|
out = ptr;
|
|
|
|
p = ptr;
|
|
|
|
for (acc = needle; (*acc != '\0') && (*p != '\0'); ++acc) {
|
|
|
|
if (*p == *acc) {
|
|
|
|
accept++;
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (accept == s) {
|
|
|
|
return (char *)out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t startswith(const char * str, const char * accept) {
|
|
|
|
size_t s = strlen(accept);
|
|
|
|
for (size_t i = 0; i < s; ++i) {
|
|
|
|
if (*str != *accept) return 0;
|
|
|
|
str++;
|
|
|
|
accept++;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
size_t strspn(const char * str, const char * accept) {
|
|
|
|
const char * ptr = str;
|
2011-02-07 23:30:17 +03:00
|
|
|
const char * acc;
|
2012-10-04 09:01:45 +04:00
|
|
|
|
|
|
|
while (*str) {
|
|
|
|
for (acc = accept; *acc; ++acc) {
|
|
|
|
if (*str == *acc) {
|
2011-02-07 23:30:17 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*acc == '\0') {
|
2012-10-04 09:01:45 +04:00
|
|
|
break;
|
2011-02-07 23:30:17 +03:00
|
|
|
}
|
2012-10-04 09:01:45 +04:00
|
|
|
|
|
|
|
str++;
|
2011-02-07 23:30:17 +03:00
|
|
|
}
|
2012-10-04 09:01:45 +04:00
|
|
|
|
|
|
|
return str - ptr;
|
2011-02-07 23:30:17 +03:00
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
char * strpbrk(const char * str, const char * accept) {
|
|
|
|
const char *acc = accept;
|
|
|
|
|
|
|
|
if (!*str) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*str) {
|
|
|
|
for (acc = accept; *acc; ++acc) {
|
|
|
|
if (*str == *acc) {
|
|
|
|
break;
|
2011-02-07 23:30:17 +03:00
|
|
|
}
|
|
|
|
}
|
2012-10-04 09:01:45 +04:00
|
|
|
if (*acc) {
|
|
|
|
break;
|
|
|
|
}
|
2011-02-07 23:30:17 +03:00
|
|
|
++str;
|
|
|
|
}
|
VESA mode switching support.
BIOS execution is provided through the `v8086` module, which provides
software emulation of an 8086 processor. It is not currently working
with some BIOSes and may (read: probably will be) replaced with another
emulator (x86emu comes to mind) at some point in the near future. In the
meantime, the default video mode for QEMU works with this and it's
enough to get us on real VESA instead of fake VBE. The `bochs` module
will be renamed in a future commit. Userspace programs have been
adjusted to work at bitrates other than 32 *POORLY*. If you write pixels
left-to-right, they should work fine. They only work with 24-bpp
otherwise, and then you need to be careful of what pixels you are
writing when, or you will overwrite things in other pixels.
You may pass a commandline argument like the following to set display
modes:
vid=vesa,1024,768
Or for stranger modes under QEMU or Bochs, use the bochs VBE
initializer:
vid=bochs,1280,720
Note that the address of the linear framebuffer is still found via
hackish probing instead of PCI or trusting the VBE information, so if
you have things in the wrong memory ranges (0xE0000000+), be prepared to
have them get read.
Once again, this entire commit is a massive hack. I am happy that it
worked, and I will continue to make it less hacky, but in the meantime,
this is what we've got.
Happy holidays.
2011-12-25 10:40:40 +04:00
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
if (*acc == '\0') {
|
|
|
|
return NULL;
|
VESA mode switching support.
BIOS execution is provided through the `v8086` module, which provides
software emulation of an 8086 processor. It is not currently working
with some BIOSes and may (read: probably will be) replaced with another
emulator (x86emu comes to mind) at some point in the near future. In the
meantime, the default video mode for QEMU works with this and it's
enough to get us on real VESA instead of fake VBE. The `bochs` module
will be renamed in a future commit. Userspace programs have been
adjusted to work at bitrates other than 32 *POORLY*. If you write pixels
left-to-right, they should work fine. They only work with 24-bpp
otherwise, and then you need to be careful of what pixels you are
writing when, or you will overwrite things in other pixels.
You may pass a commandline argument like the following to set display
modes:
vid=vesa,1024,768
Or for stranger modes under QEMU or Bochs, use the bochs VBE
initializer:
vid=bochs,1280,720
Note that the address of the linear framebuffer is still found via
hackish probing instead of PCI or trusting the VBE information, so if
you have things in the wrong memory ranges (0xE0000000+), be prepared to
have them get read.
Once again, this entire commit is a massive hack. I am happy that it
worked, and I will continue to make it less hacky, but in the meantime,
this is what we've got.
Happy holidays.
2011-12-25 10:40:40 +04:00
|
|
|
}
|
|
|
|
|
2012-10-04 09:01:45 +04:00
|
|
|
return (char *)str;
|
VESA mode switching support.
BIOS execution is provided through the `v8086` module, which provides
software emulation of an 8086 processor. It is not currently working
with some BIOSes and may (read: probably will be) replaced with another
emulator (x86emu comes to mind) at some point in the near future. In the
meantime, the default video mode for QEMU works with this and it's
enough to get us on real VESA instead of fake VBE. The `bochs` module
will be renamed in a future commit. Userspace programs have been
adjusted to work at bitrates other than 32 *POORLY*. If you write pixels
left-to-right, they should work fine. They only work with 24-bpp
otherwise, and then you need to be careful of what pixels you are
writing when, or you will overwrite things in other pixels.
You may pass a commandline argument like the following to set display
modes:
vid=vesa,1024,768
Or for stranger modes under QEMU or Bochs, use the bochs VBE
initializer:
vid=bochs,1280,720
Note that the address of the linear framebuffer is still found via
hackish probing instead of PCI or trusting the VBE information, so if
you have things in the wrong memory ranges (0xE0000000+), be prepared to
have them get read.
Once again, this entire commit is a massive hack. I am happy that it
worked, and I will continue to make it less hacky, but in the meantime,
this is what we've got.
Happy holidays.
2011-12-25 10:40:40 +04:00
|
|
|
}
|
2012-10-04 09:01:45 +04:00
|
|
|
|