Initial commit

This commit is contained in:
g1n 2021-08-04 18:14:22 +03:00
commit 823aa582e1
38 changed files with 776 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.iso
isodir
tools
sysroot

7
TODO.org Normal file
View File

@ -0,0 +1,7 @@
#+TITLE: TODO for BareBones article-based OS on C
* DONE Newline support
* TODO Implement terminal scrolling
* TODO Colors changing (for ASCII arts)
* TODO Calling Global Constructors

7
build.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
set -e
. ./headers.sh
for PROJECT in $PROJECTS; do
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE -j$(nproc) install)
done

11
clean.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
set -e
. ./config.sh
for PROJECT in $PROJECTS; do
(cd $PROJECT && $MAKE clean)
done
rm -rf sysroot
rm -rf isodir
rm -rf orion.iso

28
config.sh Normal file
View File

@ -0,0 +1,28 @@
SYSTEM_HEADER_PROJECTS="libc kernel"
PROJECTS="libc kernel"
export MAKE=${MAKE:-make}
export HOST=${HOST:-$(./default-host.sh)}
export AR=${HOST}-ar
export AS=${HOST}-as
export CC=${HOST}-gcc
export PREFIX=/usr
export EXEC_PREFIX=$PREFIX
export BOOTDIR=/boot
export LIBDIR=$EXEC_PREFIX/lib
export INCLUDEDIR=$PREFIX/include
export CFLAGS='-O2 -g'
export CPPFLAGS=''
# Configure the cross-compiler to use the desired system root.
export SYSROOT="$(pwd)/sysroot"
export CC="$CC --sysroot=$SYSROOT"
# Work around that the -elf gcc targets doesn't have a system include directory
# because it was configured with --without-headers rather than --with-sysroot.
if echo "$HOST" | grep -Eq -- '-elf($|-)'; then
export CC="$CC -isystem=$INCLUDEDIR"
fi

2
default-host.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
echo i686-elf

9
headers.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
set -e
. ./config.sh
mkdir -p "$SYSROOT"
for PROJECT in $SYSTEM_HEADER_PROJECTS; do
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install-headers)
done

15
iso.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
set -e
. ./build.sh
mkdir -p isodir
mkdir -p isodir/boot
mkdir -p isodir/boot/grub
cp sysroot/boot/orion.kernel isodir/boot/orion.kernel
cat > isodir/boot/grub/grub.cfg << EOF
menuentry "orion" {
multiboot /boot/orion.kernel
}
EOF
grub-mkrescue -o orion.iso isodir

3
kernel/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.d
*.kernel
*.o

83
kernel/Makefile Normal file
View File

@ -0,0 +1,83 @@
DEFAULT_HOST!=../default-host.sh
HOST?=DEFAULT_HOST
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)
CFLAGS?=-O2 -g
CPPFLAGS?=
LDFLAGS?=
LIBS?=
DESTDIR?=
PREFIX?=/usr/local
EXEC_PREFIX?=$(PREFIX)
BOOTDIR?=$(EXEC_PREFIX)/boot
INCLUDEDIR?=$(PREFIX)/include
CFLAGS:=$(CFLAGS) -ffreestanding -Wall -Wextra
CPPFLAGS:=$(CPPFLAGS) -D__is_kernel -Iinclude
LDFLAGS:=$(LDFLAGS)
LIBS:=$(LIBS) -nostdlib -lk -lgcc
ARCHDIR=arch/$(HOSTARCH)
include $(ARCHDIR)/make.config
CFLAGS:=$(CFLAGS) $(KERNEL_ARCH_CFLAGS)
CPPFLAGS:=$(CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)
LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS)
LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)
KERNEL_OBJS=\
$(KERNEL_ARCH_OBJS) \
kernel/kernel.o \
OBJS=\
$(ARCHDIR)/crti.o \
$(ARCHDIR)/crtbegin.o \
$(KERNEL_OBJS) \
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \
LINK_LIST=\
$(LDFLAGS) \
$(ARCHDIR)/crti.o \
$(ARCHDIR)/crtbegin.o \
$(KERNEL_OBJS) \
$(LIBS) \
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \
.PHONY: all clean install install-headers install-kernel
.SUFFIXES: .o .c .S
all: orion.kernel
orion.kernel: $(OBJS) $(ARCHDIR)/linker.ld
$(CC) -T $(ARCHDIR)/linker.ld -o $@ $(CFLAGS) $(LINK_LIST)
grub-file --is-x86-multiboot orion.kernel
$(ARCHDIR)/crtbegin.o $(ARCHDIR)/crtend.o:
OBJ=`$(CC) $(CFLAGS) $(LDFLAGS) -print-file-name=$(@F)` && cp "$$OBJ" $@
.c.o:
$(CC) -MD -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)
.S.o:
$(CC) -MD -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
clean:
rm -f orion.kernel
rm -f $(OBJS) *.o */*.o */*/*.o
rm -f $(OBJS:.o=.d) *.d */*.d */*/*.d
install: install-headers install-kernel
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.
install-kernel: orion.kernel
mkdir -p $(DESTDIR)$(BOOTDIR)
cp orion.kernel $(DESTDIR)$(BOOTDIR)
-include $(OBJS:.o=.d)

39
kernel/arch/i386/boot.S Normal file
View File

@ -0,0 +1,39 @@
# Declare constants for the multiboot header.
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set MEMINFO, 1<<1 # provide memory map
.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field
.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot
# Declare a header as in the Multiboot Standard.
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
# Reserve a stack for the initial thread.
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KiB
stack_top:
# The kernel entry point.
.section .text
.global _start
.type _start, @function
_start:
movl $stack_top, %esp
# Call the global constructors.
call _init
# Transfer control to the main kernel.
call kernel_main
# Hang if kernel_main unexpectedly returns.
cli
1: hlt
jmp 1b
.size _start, . - _start

15
kernel/arch/i386/crti.S Normal file
View File

@ -0,0 +1,15 @@
.section .init
.global _init
.type _init, @function
_init:
push %ebp
movl %esp, %ebp
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
.section .fini
.global _fini
.type _fini, @function
_fini:
push %ebp
movl %esp, %ebp
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */

9
kernel/arch/i386/crtn.S Normal file
View File

@ -0,0 +1,9 @@
.section .init
/* gcc will nicely put the contents of crtend.o's .init section here. */
popl %ebp
ret
.section .fini
/* gcc will nicely put the contents of crtend.o's .fini section here. */
popl %ebp
ret

View File

@ -0,0 +1,43 @@
/* The bootloader will look at this image and start execution at the symbol
designated at the entry point. */
ENTRY(_start)
/* Tell where the various sections of the object files will be put in the final
kernel image. */
SECTIONS
{
/* Begin putting sections at 1 MiB, a conventional place for kernels to be
loaded at by the bootloader. */
. = 1M;
/* First put the multiboot header, as it is required to be put very early
early in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
/* Read-only data. */
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
/* Read-write data (initialized) */
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
/* Read-write data (uninitialized) and stack */
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
/* The compiler may produce other sections, put them in the proper place in
in this file, if you'd like to include them in the final kernel. */
}

View File

@ -0,0 +1,8 @@
KERNEL_ARCH_CFLAGS=
KERNEL_ARCH_CPPFLAGS=
KERNEL_ARCH_LDFLAGS=
KERNEL_ARCH_LIBS=
KERNEL_ARCH_OBJS=\
$(ARCHDIR)/boot.o \
$(ARCHDIR)/tty.o \

89
kernel/arch/i386/tty.c Normal file
View File

@ -0,0 +1,89 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <kernel/tty.h>
#include "vga.h"
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
static uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000;
static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_color;
static uint16_t* terminal_buffer;
void terminal_initialize(void) {
terminal_row = 0;
terminal_column = 0;
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
terminal_buffer = VGA_MEMORY;
for (size_t y = 0; y < VGA_HEIGHT; y++) {
for (size_t x = 0; x < VGA_WIDTH; x++) {
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = vga_entry(' ', terminal_color);
}
}
}
void terminal_setcolor(uint8_t color) {
terminal_color = color;
}
void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y) {
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = vga_entry(c, color);
}
void terminal_scroll(int line) {
int loop;
int c;
for(loop = line * (VGA_WIDTH * 2) + 0xB8000; loop < VGA_WIDTH * 2; loop++) {
c = loop;
//*(loop - (VGA_WIDTH * 2)) = c;
}
}
void terminal_delete_last_line() {
int x, *ptr;
for(x = 0; x < VGA_WIDTH * 2; x++) {
ptr = 0xB8000 + (VGA_WIDTH * 2) * (VGA_HEIGHT - 1) + x;
*ptr = 0;
}
}
void terminal_putchar(char c) {
unsigned char uc = c;
terminal_putentryat(uc, terminal_color, terminal_column, terminal_row);
if (c != '\n') {
if (++terminal_column == VGA_WIDTH) {
terminal_column = 0;
if (++terminal_row == VGA_HEIGHT) {
for(int line = 1; line <= VGA_HEIGHT - 1; line++)
{
terminal_scroll(line);
}
terminal_delete_last_line();
terminal_row = VGA_HEIGHT - 1;
}
}
} else {
terminal_row += 1;
terminal_column = 0;
}
}
void terminal_write(const char* data, size_t size) {
for (size_t i = 0; i < size; i++)
terminal_putchar(data[i]);
}
void terminal_writestring(const char* data) {
terminal_write(data, strlen(data));
}

33
kernel/arch/i386/vga.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef ARCH_I386_VGA_H
#define ARCH_I386_VGA_H
#include <stdint.h>
enum vga_color {
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
};
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
return fg | bg << 4;
}
static inline uint16_t vga_entry(unsigned char uc, uint8_t color) {
return (uint16_t) uc | (uint16_t) color << 8;
}
#endif

View File

@ -0,0 +1,11 @@
#ifndef _KERNEL_TTY_H
#define _KERNEL_TTY_H
#include <stddef.h>
void terminal_initialize(void);
void terminal_putchar(char c);
void terminal_write(const char* data, size_t size);
void terminal_writestring(const char* data);
#endif

8
kernel/kernel/kernel.c Normal file
View File

@ -0,0 +1,8 @@
#include <stdio.h>
#include <kernel/tty.h>
void kernel_main(void) {
terminal_initialize();
printf("Hello from OrionOS!\n");
}

3
libc/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.a
*.d
*.o

93
libc/Makefile Normal file
View File

@ -0,0 +1,93 @@
DEFAULT_HOST!=../default-host.sh
HOST?=DEFAULT_HOST
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)
CFLAGS?=-O2 -g
CPPFLAGS?=
LDFLAGS?=
LIBS?=
DESTDIR?=
PREFIX?=/usr/local
EXEC_PREFIX?=$(PREFIX)
INCLUDEDIR?=$(PREFIX)/include
LIBDIR?=$(EXEC_PREFIX)/lib
CFLAGS:=$(CFLAGS) -ffreestanding -Wall -Wextra
CPPFLAGS:=$(CPPFLAGS) -D__is_libc -Iinclude
LIBK_CFLAGS:=$(CFLAGS)
LIBK_CPPFLAGS:=$(CPPFLAGS) -D__is_libk
ARCHDIR=arch/$(HOSTARCH)
include $(ARCHDIR)/make.config
CFLAGS:=$(CFLAGS) $(ARCH_CFLAGS)
CPPFLAGS:=$(CPPFLAGS) $(ARCH_CPPFLAGS)
LIBK_CFLAGS:=$(LIBK_CFLAGS) $(KERNEL_ARCH_CFLAGS)
LIBK_CPPFLAGS:=$(LIBK_CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)
FREEOBJS=\
$(ARCH_FREEOBJS) \
stdio/printf.o \
stdio/putchar.o \
stdio/puts.o \
stdlib/abort.o \
string/memcmp.o \
string/memcpy.o \
string/memmove.o \
string/memset.o \
string/strlen.o \
HOSTEDOBJS=\
$(ARCH_HOSTEDOBJS) \
OBJS=\
$(FREEOBJS) \
$(HOSTEDOBJS) \
LIBK_OBJS=$(FREEOBJS:.o=.libk.o)
#BINARIES=libc.a libk.a # Not ready for libc yet.
BINARIES=libk.a
.PHONY: all clean install install-headers install-libs
.SUFFIXES: .o .libk.o .c .S
all: $(BINARIES)
libc.a: $(OBJS)
$(AR) rcs $@ $(OBJS)
libk.a: $(LIBK_OBJS)
$(AR) rcs $@ $(LIBK_OBJS)
.c.o:
$(CC) -MD -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)
.c.S:
$(CC) -MD -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
.c.libk.o:
$(CC) -MD -c $< -o $@ -std=gnu11 $(LIBK_CFLAGS) $(LIBK_CPPFLAGS)
.S.libk.o:
$(CC) -MD -c $< -o $@ $(LIBK_CFLAGS) $(LIBK_CPPFLAGS)
clean:
rm -f $(BINARIES) *.a
rm -f $(OBJS) $(LIBK_OBJS) *.o */*.o */*/*.o
rm -f $(OBJS:.o=.d) $(LIBK_OBJS:.o=.d) *.d */*.d */*/*.d
install: install-headers install-libs
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.
install-libs: $(BINARIES)
mkdir -p $(DESTDIR)$(LIBDIR)
cp $(BINARIES) $(DESTDIR)$(LIBDIR)
-include $(OBJS:.o=.d)
-include $(LIBK_OBJS:.o=.d)

View File

@ -0,0 +1,8 @@
ARCH_CFLAGS=
ARCH_CPPFLAGS=
KERNEL_ARCH_CFLAGS=
KERNEL_ARCH_CPPFLAGS=
ARCH_FREEOBJS=\
ARCH_HOSTEDOBJS=\

20
libc/include/stdio.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _STDIO_H
#define _STDIO_H 1
#include <sys/cdefs.h>
#define EOF (-1)
#ifdef __cplusplus
extern "C" {
#endif
int printf(const char* __restrict, ...);
int putchar(int);
int puts(const char*);
#ifdef __cplusplus
}
#endif
#endif

17
libc/include/stdlib.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _STDLIB_H
#define _STDLIB_H 1
#include <sys/cdefs.h>
#ifdef __cplusplus
extern "C" {
#endif
__attribute__((__noreturn__))
void abort(void);
#ifdef __cplusplus
}
#endif
#endif

22
libc/include/string.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _STRING_H
#define _STRING_H 1
#include <sys/cdefs.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
int memcmp(const void*, const void*, size_t);
void* memcpy(void* __restrict, const void* __restrict, size_t);
void* memmove(void*, const void*, size_t);
void* memset(void*, int, size_t);
size_t strlen(const char*);
#ifdef __cplusplus
}
#endif
#endif

6
libc/include/sys/cdefs.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _SYS_CDEFS_H
#define _SYS_CDEFS_H 1
#define __orion_libc 1
#endif

80
libc/stdio/printf.c Normal file
View File

@ -0,0 +1,80 @@
#include <limits.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
static bool print(const char* data, size_t length) {
const unsigned char* bytes = (const unsigned char*) data;
for (size_t i = 0; i < length; i++)
if (putchar(bytes[i]) == EOF)
return false;
return true;
}
int printf(const char* restrict format, ...) {
va_list parameters;
va_start(parameters, format);
int written = 0;
while (*format != '\0') {
size_t maxrem = INT_MAX - written;
if (format[0] != '%' || format[1] == '%') {
if (format[0] == '%')
format++;
size_t amount = 1;
while (format[amount] && format[amount] != '%')
amount++;
if (maxrem < amount) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, amount))
return -1;
format += amount;
written += amount;
continue;
}
const char* format_begun_at = format++;
if (*format == 'c') {
format++;
char c = (char) va_arg(parameters, int /* char promotes to int */);
if (!maxrem) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(&c, sizeof(c)))
return -1;
written++;
} else if (*format == 's') {
format++;
const char* str = va_arg(parameters, const char*);
size_t len = strlen(str);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(str, len))
return -1;
written += len;
} else {
format = format_begun_at;
size_t len = strlen(format);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, len))
return -1;
written += len;
format += len;
}
}
va_end(parameters);
return written;
}

15
libc/stdio/putchar.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdio.h>
#if defined(__is_libk)
#include <kernel/tty.h>
#endif
int putchar(int ic) {
#if defined(__is_libk)
char c = (char) ic;
terminal_write(&c, sizeof(c));
#else
// TODO: Implement stdio and the write system call.
#endif
return ic;
}

5
libc/stdio/puts.c Normal file
View File

@ -0,0 +1,5 @@
#include <stdio.h>
int puts(const char* string) {
return printf("%s\n", string);
}

15
libc/stdlib/abort.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdio.h>
#include <stdlib.h>
__attribute__((__noreturn__))
void abort(void) {
#if defined(__is_libk)
// TODO: Add proper kernel panic.
printf("kernel: panic: abort()\n");
#else
// TODO: Abnormally terminate the process as if by SIGABRT.
printf("abort()\n");
#endif
while (1) { }
__builtin_unreachable();
}

13
libc/string/memcmp.c Normal file
View File

@ -0,0 +1,13 @@
#include <string.h>
int memcmp(const void* aptr, const void* bptr, size_t size) {
const unsigned char* a = (const unsigned char*) aptr;
const unsigned char* b = (const unsigned char*) bptr;
for (size_t i = 0; i < size; i++) {
if (a[i] < b[i])
return -1;
else if (b[i] < a[i])
return 1;
}
return 0;
}

9
libc/string/memcpy.c Normal file
View File

@ -0,0 +1,9 @@
#include <string.h>
void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) {
unsigned char* dst = (unsigned char*) dstptr;
const unsigned char* src = (const unsigned char*) srcptr;
for (size_t i = 0; i < size; i++)
dst[i] = src[i];
return dstptr;
}

14
libc/string/memmove.c Normal file
View File

@ -0,0 +1,14 @@
#include <string.h>
void* memmove(void* dstptr, const void* srcptr, size_t size) {
unsigned char* dst = (unsigned char*) dstptr;
const unsigned char* src = (const unsigned char*) srcptr;
if (dst < src) {
for (size_t i = 0; i < size; i++)
dst[i] = src[i];
} else {
for (size_t i = size; i != 0; i--)
dst[i-1] = src[i-1];
}
return dstptr;
}

8
libc/string/memset.c Normal file
View File

@ -0,0 +1,8 @@
#include <string.h>
void* memset(void* bufptr, int value, size_t size) {
unsigned char* buf = (unsigned char*) bufptr;
for (size_t i = 0; i < size; i++)
buf[i] = (unsigned char) value;
return bufptr;
}

8
libc/string/strlen.c Normal file
View File

@ -0,0 +1,8 @@
#include <string.h>
size_t strlen(const char* str) {
size_t len = 0;
while (str[len])
len++;
return len;
}

5
qemu-only-kernel.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
set -e
. ./build.sh
qemu-system-x86_64 -kernel sysroot/boot/orion.kernel

5
qemu.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
set -e
. ./iso.sh
qemu-system-x86_64 -cdrom orion.iso

6
target-triplet-to-arch.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
if echo "$1" | grep -Eq 'i[[:digit:]]86-'; then
echo i386
else
echo "$1" | grep -Eo '^[[:alnum:]_]*'
fi