/tmp/sos-code-article8/drivers/mem.c (2005-07-01 16:39:47.000000000 +0200
) |
|
../sos-code-article9/drivers/mem.c (2005-12-28 11:44:56.000000000 +0100
) |
|
|
|
#include <sos/kmem_slab.h> | #include <sos/kmem_slab.h> |
#include <sos/list.h> | #include <sos/list.h> |
#include <hwcore/paging.h> | #include <hwcore/paging.h> |
| #include <drivers/devices.h> |
| #include <sos/kmem_vmm.h> |
| #include <sos/uaccess.h> |
| #include <sos/chardev.h> |
| |
#include "mem.h" | #include "mem.h" |
| |
|
|
| |
/** The function responsible for mapping the /dev/kmem resource in | /** The function responsible for mapping the /dev/kmem resource in |
user space */ | user space */ |
| static |
sos_ret_t sos_dev_kmem_map(struct sos_umem_vmm_as * dest_as, | sos_ret_t sos_dev_kmem_map(struct sos_umem_vmm_as * dest_as, |
sos_uaddr_t *uaddr, | sos_uaddr_t *uaddr, |
sos_size_t size, | sos_size_t size, |
|
|
| |
/** The function responsible for mapping the /dev/mem resource in | /** The function responsible for mapping the /dev/mem resource in |
user space */ | user space */ |
| static |
sos_ret_t sos_dev_physmem_map(struct sos_umem_vmm_as * dest_as, | sos_ret_t sos_dev_physmem_map(struct sos_umem_vmm_as * dest_as, |
sos_uaddr_t *uaddr, | sos_uaddr_t *uaddr, |
sos_size_t size, | sos_size_t size, |
|
|
| |
return SOS_OK; | return SOS_OK; |
} | } |
| |
| |
| /* |
| * /dev/mem and /dev/kmem character device operations |
| * |
| * the "custom_data" field of the FS node is used to store the total |
| * number of pages available |
| */ |
| #define GET_DEV_SIZE(fsnode) \ |
| ((sos_size_t)(fsnode)->custom_data) |
| |
| static sos_ret_t dev_mem_fs_open(struct sos_fs_node * fsnode, |
| struct sos_fs_opened_file * of, |
| void * chardev_class_custom_data) |
| { |
| /* Make sure the device is supported by this driver and compute its |
| "size" (use the custom_data field to store it) */ |
| switch (fsnode->dev_id.device_instance) |
| { |
| /* For /dev/kmem, go to the end of the kernel mapping */ |
| case SOS_CHARDEV_KMEM_MINOR: |
| fsnode->custom_data = (void*)SOS_PAGING_BASE_USER_ADDRESS; |
| return SOS_OK; |
| break; |
| |
| /* For /dev/mem, go to the end of physical memory */ |
| case SOS_CHARDEV_PHYSMEM_MINOR: |
| { |
| sos_size_t ram_pages = 0; |
| sos_physmem_get_state(& ram_pages, NULL); |
| fsnode->custom_data = (void*)(ram_pages << SOS_PAGE_SHIFT); |
| } |
| return SOS_OK; |
| break; |
| |
| default: |
| break; |
| } |
| |
| return -SOS_ENODEV; |
| } |
| |
| |
| static sos_ret_t dev_mem_fs_seek(struct sos_fs_opened_file *this, |
| sos_lsoffset_t offset, |
| sos_seek_whence_t whence, |
| /* out */ sos_lsoffset_t * result_position) |
| { |
| /* Make sure the device is supported by this driver */ |
| struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry); |
| |
| /* Artificiallly update the position in the "file" */ |
| sos_lsoffset_t ref_offs; |
| sos_lsoffset_t dev_size = GET_DEV_SIZE(fsnode); |
| |
| *result_position = this->position; |
| switch (whence) |
| { |
| case SOS_SEEK_SET: |
| ref_offs = 0; |
| break; |
| |
| case SOS_SEEK_CUR: |
| ref_offs = this->position; |
| break; |
| |
| case SOS_SEEK_END: |
| ref_offs = dev_size; |
| break; |
| |
| default: |
| return -SOS_EINVAL; |
| } |
| |
| /* Forbid accesses "before" the start of the device */ |
| if (offset < -ref_offs) |
| return -SOS_EINVAL; |
| |
| /* Forbid accesses "after" the end of the device */ |
| else if (ref_offs + offset > dev_size) |
| return -SOS_EINVAL; |
| |
| this->position = ref_offs + offset; |
| *result_position = this->position; |
| return SOS_OK; |
| } |
| |
| |
| typedef enum { DO_READ, DO_WRITE } dev_mem_access_type_t; |
| static sos_ret_t dev_mem_fs_access(struct sos_fs_opened_file *this, |
| sos_uaddr_t user_buf, |
| sos_size_t * /* in/out */len, |
| dev_mem_access_type_t access_type) |
| { |
| struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry); |
| sos_vaddr_t physmem_transfer_kernel_page = 0; /* Used for /dev/mem only */ |
| sos_uoffset_t offs; |
| sos_size_t accesslen = 0; |
| |
| /* Readjust copy length to match the size of the device */ |
| if (this->position + *len >= GET_DEV_SIZE(fsnode)) |
| *len = GET_DEV_SIZE(fsnode) - this->position; |
| |
| /* Ignore zero-size requests */ |
| if (*len <= 0) |
| return SOS_OK; |
| |
| /* For /dev/mem device, prepare a kernel page to copy the physical |
| pages before transferring to user space */ |
| if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance) |
| { |
| physmem_transfer_kernel_page = sos_kmem_vmm_alloc(1, 0); |
| if (! physmem_transfer_kernel_page) |
| return -SOS_ENOMEM; |
| } |
| |
| /* Try to copy the data in page-size chunks */ |
| offs = this->position; |
| while (offs < this->position + *len) |
| { |
| /* Retrieve page address of data in kernel memory */ |
| sos_uoffset_t page_boundary = SOS_PAGE_ALIGN_INF(offs); |
| sos_vaddr_t page_vaddr; |
| sos_uoffset_t offset_in_page; |
| sos_uoffset_t accesslen_in_page; |
| sos_ret_t retval; |
| |
| /* For /dev/mem device, we need to map the page in kernel memory |
| before */ |
| if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance) |
| { |
| retval = sos_paging_map(page_boundary, |
| physmem_transfer_kernel_page, |
| FALSE, |
| (access_type==DO_WRITE)? |
| SOS_VM_MAP_PROT_WRITE |
| :SOS_VM_MAP_PROT_READ); |
| if (SOS_OK != retval) |
| break; |
| |
| page_vaddr = physmem_transfer_kernel_page; |
| } |
| /* For /dev/kmem device, the page should already be in kernel space */ |
| else if (! sos_kmem_vmm_is_valid_vaddr(page_boundary)) |
| break; /* No: page is not mapped in kernel space ! */ |
| else |
| page_vaddr = page_boundary; /* Yes, page is mapped */ |
| |
| /* Now copy the data from kernel to user space */ |
| offset_in_page = offs - page_boundary; |
| accesslen_in_page = SOS_PAGE_SIZE - offset_in_page; |
| if (accesslen + accesslen_in_page > *len) |
| accesslen_in_page = *len - accesslen; |
| |
| if (access_type==DO_WRITE) |
| retval = sos_memcpy_from_user(page_vaddr + offset_in_page, |
| user_buf + accesslen, |
| accesslen_in_page); |
| else |
| retval = sos_memcpy_to_user(user_buf + accesslen, |
| page_vaddr + offset_in_page, |
| accesslen_in_page); |
| |
| /* Now, for /dev/mem, unmap the page from kernel */ |
| if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance) |
| sos_paging_unmap(physmem_transfer_kernel_page); |
| |
| /* Go to next page if possible */ |
| if (retval < 0) |
| break; |
| |
| accesslen += retval; |
| /* If transfer was interrupted, stop here */ |
| if (retval < accesslen_in_page) |
| break; |
| |
| /* Go on to next page */ |
| offs = page_boundary + SOS_PAGE_SIZE; |
| } |
| |
| /* Release the temporary page for physical mem transfers */ |
| if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance) |
| sos_kmem_vmm_free(physmem_transfer_kernel_page); |
| |
| /* Update the position in the "file" */ |
| *len = accesslen; |
| this->position += accesslen; |
| return SOS_OK; |
| } |
| |
| |
| static sos_ret_t dev_mem_fs_read(struct sos_fs_opened_file *this, |
| sos_uaddr_t dest_buf, |
| sos_size_t * /* in/out */len) |
| { |
| return dev_mem_fs_access(this, dest_buf, len, DO_READ); |
| } |
| |
| |
| static sos_ret_t dev_mem_fs_write(struct sos_fs_opened_file *this, |
| sos_uaddr_t src_buf, |
| sos_size_t * /* in/out */len) |
| { |
| return dev_mem_fs_access(this, src_buf, len, DO_WRITE); |
| } |
| |
| |
| static sos_ret_t dev_mem_fs_mmap(struct sos_fs_opened_file *this, |
| sos_uaddr_t *uaddr, sos_size_t size, |
| sos_ui32_t access_rights, |
| sos_ui32_t flags, |
| sos_luoffset_t offset) |
| { |
| struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry); |
| if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance) |
| return sos_dev_physmem_map(sos_process_get_address_space(this->owner), |
| uaddr, size, offset, access_rights, flags); |
| |
| return sos_dev_kmem_map(sos_process_get_address_space(this->owner), |
| uaddr, size, offset, access_rights, flags); |
| } |
| |
| |
| static struct sos_chardev_ops dev_mem_fs_ops |
| = (struct sos_chardev_ops) { |
| .open = dev_mem_fs_open, |
| .close = NULL, |
| .seek = dev_mem_fs_seek, |
| .read = dev_mem_fs_read, |
| .write = dev_mem_fs_write, |
| .mmap = dev_mem_fs_mmap, |
| .fcntl = NULL, |
| .ioctl = NULL |
| }; |
| |
| |
| sos_ret_t sos_dev_mem_chardev_setup() |
| { |
| return sos_chardev_register_class(SOS_CHARDEV_MEM_MAJOR, |
| & dev_mem_fs_ops, |
| NULL); |
| } |
| |
/tmp/sos-code-article8/drivers/serial.c (1970-01-01 01:00:00.000000000 +0100
) |
|
../sos-code-article9/drivers/serial.c (2005-12-28 11:44:56.000000000 +0100
) |
|
|
|
| /* Copyright (C) 2000 David Decotigny, The KOS Team |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. |
| */ |
| |
| #include <sos/errno.h> |
| #include <hwcore/ioports.h> |
| #include <sos/klibc.h> |
| #include <hwcore/irq.h> |
| #include <drivers/devices.h> |
| |
| #include "tty.h" |
| |
| #define SERIAL_BAUDRATE_MAX 115200 |
| |
| /* Default parameters */ |
| #ifndef DEBUG_SERIAL_PORT |
| # define DEBUG_SERIAL_PORT 0 |
| #endif |
| #ifndef DEBUG_SERIAL_SPEED |
| # define DEBUG_SERIAL_SPEED 9600 |
| #endif |
| |
| /* The offsets of UART registers. */ |
| #define UART_TX 0 |
| #define UART_RX 0 |
| #define UART_DLL 0 |
| #define UART_IER 1 |
| #define UART_DLH 1 |
| #define UART_IIR 2 |
| #define UART_FCR 2 |
| #define UART_LCR 3 |
| #define UART_MCR 4 |
| #define UART_LSR 5 |
| #define UART_MSR 6 |
| #define UART_SR 7 |
| |
| /* For LSR bits. */ |
| #define UART_DATA_READY 0x01 |
| #define UART_EMPTY_TRANSMITTER 0x20 |
| |
| /* The type of parity. */ |
| #define UART_NO_PARITY 0x00 |
| #define UART_ODD_PARITY 0x08 |
| #define UART_EVEN_PARITY 0x18 |
| |
| /* The type of word length. */ |
| #define UART_5BITS_WORD 0x00 |
| #define UART_6BITS_WORD 0x01 |
| #define UART_7BITS_WORD 0x02 |
| #define UART_8BITS_WORD 0x03 |
| |
| /* The type of the length of stop bit. */ |
| #define UART_1_STOP_BIT 0x00 |
| #define UART_2_STOP_BITS 0x04 |
| |
| /* the switch of DLAB. */ |
| #define UART_DLAB 0x80 |
| |
| /* Enable the FIFO. */ |
| #define UART_ENABLE_FIFO 0xC7 |
| |
| /* Turn on DTR, RTS, and OUT2. */ |
| #define UART_ENABLE_MODEM 0x0B |
| |
| |
| static struct |
| { |
| unsigned short iobase; |
| unsigned short is_enabled; |
| struct tty_device *tty; |
| } _serial_config [] = { { 0x3f8, FALSE }, |
| { 0x2f8, FALSE }, |
| { 0x3e8, FALSE }, |
| { 0x2e8, FALSE } }; |
| |
| #define SERIAL_PORT_MAX 4 |
| |
| #define serial_inb inb |
| #define serial_outb(port,val) outb(val,port) |
| |
| inline static int |
| serial_isready (unsigned short port) |
| { |
| unsigned char status; |
| |
| status = serial_inb (port + UART_LSR); |
| return (status & UART_DATA_READY) ? : -1; |
| } |
| |
| |
| static char |
| serial_getchar (unsigned short unit) |
| { |
| if(unit >= SERIAL_PORT_MAX |
| || _serial_config[unit].is_enabled == FALSE) |
| return -1; |
| |
| /* Wait until data is ready. */ |
| while ((serial_inb (_serial_config[unit].iobase + UART_LSR) |
| & UART_DATA_READY) == 0) |
| ; |
| |
| /* Read and return the data. */ |
| return serial_inb (_serial_config[unit].iobase + UART_RX); |
| } |
| |
| |
| /* 0 on success */ |
| static int |
| serial_putchar (unsigned short port, char c) |
| { |
| /* Perhaps a timeout is necessary. */ |
| int timeout = 10000; |
| |
| /* Wait until the transmitter holding register is empty. */ |
| while ((serial_inb (port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0) |
| if (--timeout == 0) |
| /* There is something wrong. But what can I do? */ |
| return -1; |
| |
| serial_outb (port + UART_TX, c); |
| return 0; |
| } |
| |
| static char serial_printk_buf[1024]; |
| |
| inline static int serial_prints(unsigned short unit, const char *str) |
| { |
| const char *c; |
| unsigned short port; |
| |
| if(unit >= SERIAL_PORT_MAX |
| || _serial_config[unit].is_enabled == FALSE) |
| return -1; |
| |
| port = _serial_config[unit].iobase; |
| |
| for (c = str; *c != '\0'; c++) |
| serial_putchar(port, *c); |
| |
| |
| return (int) (c-str); |
| } |
| |
| int sos_serial_printf(unsigned short unit, const char *format, ...) |
| { |
| va_list args; |
| int len; |
| |
| va_start(args, format); |
| len=vsnprintf(serial_printk_buf,sizeof(serial_printk_buf),format,args); |
| |
| return serial_prints(unit, serial_printk_buf); |
| } |
| |
| |
| static void serial_irq_handler (int irq_level) |
| { |
| unsigned char chr; |
| |
| if (irq_level == SOS_IRQ_COM1) |
| { |
| char c[2]; |
| chr = serial_inb (_serial_config[0].iobase + UART_RX); |
| |
| /* Little hacks to get it to work with Qemu serial port |
| emulation. */ |
| if (chr == '\r') |
| chr = '\n'; |
| else if (chr == 127) |
| chr = '\b'; |
| |
| /* Build a null-terminated string */ |
| c[0] = chr; |
| c[1] = '\0'; |
| |
| tty_add_chars (_serial_config[0].tty, c); |
| } |
| } |
| |
| static sos_ret_t sos_serial_putchar (char c) |
| { |
| sos_ret_t ret; |
| int i; |
| |
| /* The serial port doesn't understand '\b', but requires ANSI |
| commands instead. So we emulate '\b' by outputing "\e[D \e[D" |
| which basically goes backward one character, prints a space and |
| goes backward one character again. */ |
| if (c == '\b') |
| { |
| const char *str = "\e[D \e[D"; |
| |
| for (i = 0; i < strlen(str); i++) |
| { |
| ret = serial_putchar (_serial_config[0].iobase, str[i]); |
| if (ret != SOS_OK) |
| return ret; |
| } |
| |
| return SOS_OK; |
| } |
| |
| return serial_putchar (_serial_config[0].iobase, c); |
| } |
| |
| |
| /* OK On success */ |
| sos_ret_t sos_serial_subsystem_setup (sos_bool_t enable) |
| { |
| unsigned short div = 0; |
| unsigned char status = 0; |
| unsigned short serial_port; |
| |
| unsigned short unit = 0; |
| unsigned int speed = 115200; |
| int word_len = UART_8BITS_WORD; |
| int parity = UART_NO_PARITY; |
| int stop_bit_len = UART_1_STOP_BIT; |
| |
| if (unit >= SERIAL_PORT_MAX) |
| return -1; |
| |
| serial_port = _serial_config[unit].iobase; |
| |
| /* Turn off the interrupt. */ |
| serial_outb (serial_port + UART_IER, 0); |
| |
| /* Set DLAB. */ |
| serial_outb (serial_port + UART_LCR, UART_DLAB); |
| |
| /* Set the baud rate. */ |
| if (speed > SERIAL_BAUDRATE_MAX) |
| return -1; |
| |
| div = SERIAL_BAUDRATE_MAX / speed; |
| |
| serial_outb (serial_port + UART_DLL, div & 0xFF); |
| serial_outb (serial_port + UART_DLH, div >> 8); |
| |
| /* Set the line status. */ |
| status |= parity | word_len | stop_bit_len; |
| serial_outb (serial_port + UART_LCR, status); |
| |
| /* Enable the FIFO. */ |
| serial_outb (serial_port + UART_FCR, UART_ENABLE_FIFO); |
| |
| /* Turn on DTR, RTS, and OUT2. */ |
| serial_outb (serial_port + UART_MCR, UART_ENABLE_MODEM); |
| |
| /* Drain the input buffer. */ |
| while (serial_isready (serial_port) != -1) |
| (void) serial_getchar (unit); |
| |
| _serial_config[unit].is_enabled = TRUE; |
| |
| return SOS_OK; |
| } |
| |
| |
| /* Cannot be placed in sos_serial_subsystem_init() because when it |
| gets called, the IRQ handling subsystem is not yet initialized */ |
| sos_ret_t sos_ttyS0_subsystem_setup (void) |
| { |
| sos_ret_t ret; |
| |
| /* FIXME */ |
| ret = tty_create (SOS_CHARDEV_SERIAL_MINOR, sos_serial_putchar, |
| & _serial_config[0].tty); |
| if (SOS_OK != ret) |
| return ret; |
| |
| sos_irq_set_routine (SOS_IRQ_COM1, serial_irq_handler); |
| |
| /* Enable interrupts */ |
| serial_outb (_serial_config[0].iobase + UART_IER, 1); |
| |
| return SOS_OK; |
| } |
| |
/tmp/sos-code-article8/drivers/tty.c (1970-01-01 01:00:00.000000000 +0100
) |
|
../sos-code-article9/drivers/tty.c (2005-12-28 11:44:56.000000000 +0100
) |
|
|
|
| /* Copyright (C) 2005 Thomas Petazzoni, David Decotigny |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. |
| */ |
| |
| #include <sos/types.h> |
| #include <sos/assert.h> |
| #include <sos/errno.h> |
| #include <sos/fs.h> |
| #include <sos/ksynch.h> |
| #include <sos/kwaitq.h> |
| #include <sos/uaccess.h> |
| #include <sos/kmalloc.h> |
| #include <sos/list.h> |
| #include <sos/chardev.h> |
| #include <drivers/devices.h> |
| |
| #include "tty.h" |
| |
| #define TTY_BUFFER_LEN 64 |
| #define TTY_NAME_LEN 16 |
| |
| struct tty_device { |
| sos_ui32_t instance; |
| unsigned int open_count; |
| char buffer[TTY_BUFFER_LEN]; |
| unsigned int buffer_read; |
| unsigned int buffer_write; |
| struct sos_ksema sem; |
| struct sos_kwaitq wq; |
| sos_ret_t (*write)(char c); |
| unsigned int param; |
| struct tty_device *next, *prev; |
| }; |
| |
| static struct tty_device *tty_device_list; |
| |
| static struct tty_device * |
| tty_device_find (sos_ui32_t instance) |
| { |
| struct tty_device *t; |
| int n; |
| |
| list_foreach (tty_device_list, t, n) |
| { |
| if (t->instance == instance) |
| return t; |
| } |
| |
| return NULL; |
| } |
| |
| static sos_ret_t tty_read(struct sos_fs_opened_file *this, |
| sos_uaddr_t dest_buf, sos_size_t *len) |
| { |
| sos_size_t count = 0; |
| struct tty_device *t; |
| sos_ret_t ret; |
| |
| t = (struct tty_device *) this->custom_data; |
| |
| if (*len == 0) |
| return SOS_OK; |
| |
| while (1) |
| { |
| char c; |
| |
| /* Take the semaphore */ |
| sos_ksema_down (& t->sem, NULL); |
| |
| /* No keys available in the ring buffer, wait until the |
| add_chars callback wakes us up */ |
| if (t->buffer_read == t->buffer_write) |
| { |
| sos_ksema_up (& t->sem); |
| sos_kwaitq_wait (& t->wq, NULL); |
| |
| /* Go back to begining of loop: maybe someone else stole the |
| semaphore */ |
| continue; |
| } |
| |
| c = t->buffer[t->buffer_read]; |
| |
| /* Copy the received character from the ring buffer to the |
| destination buffer */ |
| ret = sos_memcpy_to_user (dest_buf, |
| (sos_vaddr_t) & t->buffer[t->buffer_read], |
| sizeof (char)); |
| if (sizeof(char) != ret) |
| { |
| *len = count; |
| sos_ksema_up (& t->sem); |
| return ret; |
| } |
| |
| dest_buf++; |
| |
| /* Update the ring buffer read pointer */ |
| t->buffer_read++; |
| if (t->buffer_read == TTY_BUFFER_LEN) |
| t->buffer_read = 0; |
| |
| count++; |
| |
| if (t->param & SOS_IOCTLPARAM_TTY_ECHO) |
| t->write (c); |
| |
| sos_ksema_up (& t->sem); |
| |
| /* Did we read enough bytes ? */ |
| if (count == *len |
| || (c == '\n' && t->param & SOS_IOCTLPARAM_TTY_CANON)) |
| break; |
| } |
| |
| *len = count; |
| return SOS_OK; |
| } |
| |
| |
| static sos_ret_t tty_write(struct sos_fs_opened_file *this, |
| sos_uaddr_t src_buf, sos_size_t *len) |
| { |
| struct tty_device *t; |
| char c; |
| int i; |
| sos_ret_t ret; |
| |
| t = (struct tty_device *) this->custom_data; |
| |
| for (i = 0; i < *len; i++) |
| { |
| ret = sos_memcpy_from_user ((sos_vaddr_t) & c, src_buf, sizeof(char)); |
| if (sizeof(char) != ret) |
| { |
| *len = i; |
| return ret; |
| } |
| |
| sos_ksema_down (& t->sem, NULL); |
| t->write (c); |
| sos_ksema_up (& t->sem); |
| |
| src_buf++; |
| } |
| |
| return SOS_OK; |
| } |
| |
| |
| static sos_ret_t tty_ioctl(struct sos_fs_opened_file *this, int req_id, |
| sos_ui32_t req_arg) |
| { |
| struct tty_device *t; |
| |
| if (req_arg != SOS_IOCTLPARAM_TTY_ECHO |
| && req_arg != SOS_IOCTLPARAM_TTY_CANON) |
| return -SOS_EINVAL; |
| |
| t = (struct tty_device *) this->custom_data; |
| |
| sos_ksema_down (& t->sem, NULL); |
| |
| switch (req_id) |
| { |
| case SOS_IOCTL_TTY_SETPARAM: |
| t->param |= req_arg; |
| break; |
| |
| case SOS_IOCTL_TTY_RESETPARAM: |
| t->param &= ~req_arg; |
| break; |
| |
| default: |
| sos_ksema_up (& t->sem); |
| return -SOS_EINVAL; |
| } |
| |
| sos_ksema_up (& t->sem); |
| |
| return SOS_OK; |
| } |
| |
| static sos_ret_t tty_open(struct sos_fs_node * fsnode, |
| struct sos_fs_opened_file * of, |
| void * chardev_class_custom_data) |
| { |
| struct tty_device *t; |
| |
| t = tty_device_find (fsnode->dev_id.device_instance); |
| if (t == NULL) |
| return -SOS_ENOENT; |
| |
| sos_ksema_down (& t->sem, NULL); |
| of->custom_data = t; |
| t->open_count ++; |
| sos_ksema_up (& t->sem); |
| |
| return SOS_OK; |
| } |
| |
| |
| static sos_ret_t tty_close(struct sos_fs_opened_file *of, |
| void *custom_data) |
| { |
| struct tty_device *t; |
| |
| t = (struct tty_device *) of->custom_data; |
| |
| sos_ksema_down (& t->sem, NULL); |
| t->open_count --; |
| sos_ksema_up (& t->sem); |
| |
| return SOS_OK; |
| } |
| |
| void tty_add_chars (struct tty_device *t, const char *s) |
| { |
| sos_ksema_down (& t->sem, NULL); |
| while (*s) |
| { |
| /* Add all characters to the ring buffer */ |
| t->buffer[t->buffer_write] = *s; |
| t->buffer_write++; |
| if (t->buffer_write == TTY_BUFFER_LEN) |
| t->buffer_write = 0; |
| s++; |
| } |
| sos_ksema_up (& t->sem); |
| |
| /* Wake up a possibly waiting thread */ |
| sos_kwaitq_wakeup (& t->wq, SOS_KWQ_WAKEUP_ALL, SOS_OK); |
| } |
| |
| struct sos_chardev_ops tty_ops = { |
| .read = tty_read, |
| .write = tty_write, |
| .open = tty_open, |
| .close = tty_close, |
| .ioctl = tty_ioctl |
| }; |
| |
| sos_ret_t tty_create (sos_ui32_t device_instance, |
| sos_ret_t (*write_func) (char c), |
| struct tty_device **tty_out) |
| { |
| struct tty_device *tty; |
| |
| if (tty_device_find (device_instance) != NULL) |
| return -SOS_EBUSY; |
| |
| tty = (struct tty_device *) sos_kmalloc (sizeof(struct tty_device), 0); |
| if (tty == NULL) |
| return -SOS_ENOMEM; |
| |
| memset (tty->buffer, 0, sizeof(tty->buffer)); |
| tty->open_count = 0; |
| tty->instance = device_instance; |
| tty->write = write_func; |
| tty->buffer_read = 0; |
| tty->buffer_write = 0; |
| tty->param = SOS_IOCTLPARAM_TTY_CANON; |
| sos_kwaitq_init(& tty->wq, "tty", SOS_KWQ_ORDER_FIFO); |
| sos_ksema_init(& tty->sem, "tty", 1, SOS_KWQ_ORDER_FIFO); |
| |
| list_add_tail (tty_device_list, tty); |
| |
| *tty_out = tty; |
| |
| return SOS_OK; |
| } |
| |
| sos_ret_t tty_remove (struct tty_device *tty) |
| { |
| if (tty == NULL) |
| return -SOS_EINVAL; |
| |
| if (SOS_OK != sos_ksema_trydown (& tty->sem)) |
| return -SOS_EBUSY; |
| |
| if (tty->open_count != 0) |
| return -SOS_EBUSY; |
| |
| sos_kwaitq_dispose (& tty->wq); |
| list_delete (tty_device_list, tty); |
| |
| sos_kfree ((sos_vaddr_t) tty); |
| |
| return SOS_OK; |
| } |
| |
| sos_ret_t tty_subsystem_setup (void) |
| { |
| list_init (tty_device_list); |
| return sos_chardev_register_class (SOS_CHARDEV_TTY_MAJOR, |
| & tty_ops, NULL); |
| } |
| |
| sos_ret_t tty_subsystem_cleanup (void) |
| { |
| return sos_chardev_unregister_class (SOS_CHARDEV_TTY_MAJOR); |
| } |
| |
| |
/tmp/sos-code-article8/drivers/x86_videomem.c (2005-07-01 16:39:47.000000000 +0200
) |
|
../sos-code-article9/drivers/x86_videomem.c (2005-12-28 11:44:56.000000000 +0100
) |
|
|
|
modify it under the terms of the GNU General Public License | modify it under the terms of the GNU General Public License |
as published by the Free Software Foundation; either version 2 | as published by the Free Software Foundation; either version 2 |
of the License, or (at your option) any later version. | of the License, or (at your option) any later version. |
| |
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. | GNU General Public License for more details. |
| |
along with this program; if not, write to the Free Software | along with this program; if not, write to the Free Software |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
USA. | USA. |
#include <sos/klibc.h> | #include <sos/klibc.h> |
#include <hwcore/ioports.h> | #include <hwcore/ioports.h> |
|
|
#define LINES 25 | #define LINES 25 |
#define COLUMNS 80 | #define COLUMNS 80 |
| |
| /* |
| * VGA ports and commands. |
| * |
| * @see Ralf Brown's interrupt (and port) list |
| * http://www-2.cs.cmu.edu/~ralf/files.html |
| */ |
| |
| /* VGA ports */ |
| #define VGA_COMMAND_PORT 0x3D4 |
| #define VGA_DATA_PORT 0x3D5 |
| |
| /* VGA commands */ |
| #define VGA_SET_CURSOR_START 0xA |
| #define VGA_SET_CURSOR_END 0xB |
| #define VGA_SET_CURSOR_HIGH 0xE |
| #define VGA_SET_CURSOR_LOW 0xF |
| |
/** The structure of a character element in the video memory. @see | /** The structure of a character element in the video memory. @see |
http://webster.cs.ucr.edu/AoA DOS edition chapter 23 */ | http://webster.cs.ucr.edu/AoA DOS edition chapter 23 */ |
|
|
| |
sos_ret_t sos_x86_videomem_setup(void) | sos_ret_t sos_x86_videomem_setup(void) |
{ | { |
/* | |
* Hide cursor. @see Ralf Brown's interrupt (and port) list | |
* http://www-2.cs.cmu.edu/~ralf/files.html | |
*/ | |
#define CRT_REG_INDEX 0x3d4 | |
#define CRT_REG_DATA 0x3d5 | |
| |
start") */ | start") */ |
outb(0x0a, CRT_REG_INDEX); | outb(0x0a, VGA_COMMAND_PORT); |
/* (RBIL Tables 708 & 654) CRT Register 0xa => bit 5 = cursor OFF */ | /* (RBIL Tables 708 & 654) CRT Register 0xa => bit 5 = cursor OFF */ |
outb(1 << 5, CRT_REG_DATA); | outb(1 << 5, VGA_DATA_PORT); |
return SOS_OK; | return SOS_OK; |
} | } |
|
|
(*video)[i].attribute = attribute; | (*video)[i].attribute = attribute; |
} | } |
| |
return SOS_OK; | return SOS_OK; |
| |
| |
|
|
| |
if (video_offs >= LINES*COLUMNS) | if (video_offs >= LINES*COLUMNS) |
return -SOS_EINVAL; | return -SOS_EINVAL; |
| |
{ | { |
(*video)[video_offs].character = (unsigned char)*str; | (*video)[video_offs].character = (unsigned char)*str; |
|
|
| |
if (video_offs >= LINES*COLUMNS) | if (video_offs >= LINES*COLUMNS) |
return -SOS_EINVAL; | return -SOS_EINVAL; |
| |
(*video)[video_offs].attribute = attribute; | (*video)[video_offs].attribute = attribute; |
| |
|
|
{ | { |
char buff[256]; | char buff[256]; |
va_list ap; | va_list ap; |
| |
vsnprintf(buff, sizeof(buff), format, ap); | vsnprintf(buff, sizeof(buff), format, ap); |
va_end(ap); | va_end(ap); |
| |
} | } |
| |
| |
| /* |
| * Console that supports scrolling, based on the low-level code |
| * above. This console only takes part of the screen, starting at row |
| * CONSOLE_ROW_START. The rows before that one are free for use by the |
| * kernel debugging messages. |
| */ |
| |
| /* Current row in the high-level console. Must be signed, because of |
| computations inside sos_screen_putchar() */ |
| static int row; |
| |
| /* Current column in the high-level console. Must be signed, because |
| of computations inside sos_screen_putchar() */ |
| static int col; |
| |
| /* The limit between the low-level console, accessible to the kernel, |
| and the high-level console, accessible to the user applications |
| through the sos_screen_putchar() function. */ |
| #define CONSOLE_ROW_START 12 |
| |
| static void sos_screen_set_cursor (unsigned int row, unsigned int col) |
| { |
| unsigned int pos; |
| |
| pos = (row * COLUMNS + col); |
| |
| outb(VGA_SET_CURSOR_HIGH, VGA_COMMAND_PORT); |
| outb( (pos >> 8), VGA_DATA_PORT); |
| outb(VGA_SET_CURSOR_LOW, VGA_COMMAND_PORT); |
| outb( (pos & 0xFF), VGA_DATA_PORT); |
| } |
| |
| sos_ret_t sos_screen_putchar (char c) |
| { |
| if (c == '\r') |
| { |
| /* Go to first row */ |
| col = 0; |
| } |
| |
| /* New line */ |
| else if (c == '\n') |
| { |
| /* Go to next line */ |
| col = 0; |
| row ++; |
| } |
| |
| /* Remove the last character */ |
| else if (c == '\b') |
| { |
| /* Next character should be displayed instead of the current |
| one */ |
| col --; |
| |
| /* Handle the case where we're at the beginning of a line */ |
| if (col < 0) |
| { |
| row --; |
| col = COLUMNS-1; |
| |
| if (row < CONSOLE_ROW_START) |
| { |
| row = CONSOLE_ROW_START; |
| col = 0; |
| } |
| } |
| |
| /* Replace the current character with a space */ |
| sos_x86_videomem_putchar |
| (row, col, SOS_X86_VIDEO_FG_BLUE | SOS_X86_VIDEO_BG_LTGRAY, ' '); |
| } |
| else if (c != 0) |
| { |
| sos_x86_videomem_putchar |
| (row, col, SOS_X86_VIDEO_FG_BLUE | SOS_X86_VIDEO_BG_LTGRAY, c); |
| col++; |
| if (col == COLUMNS) |
| { |
| col = 0; |
| row++; |
| } |
| } |
| |
| /* Need to scroll ? */ |
| if (row == LINES) |
| { |
| int i; |
| |
| /* Copy each line in the previous line */ |
| for (i = CONSOLE_ROW_START; i < LINES; i++) |
| memcpy ((char*) video + i * COLUMNS * 2, |
| (char*) video + ((i + 1) * COLUMNS * 2), |
| COLUMNS * 2); |
| |
| /* Reset the last line of the console */ |
| for (i = 0; i < COLUMNS; i++) |
| sos_x86_videomem_putchar |
| (LINES-1, i, SOS_X86_VIDEO_FG_BLUE | SOS_X86_VIDEO_BG_LTGRAY, ' '); |
| |
| row--; |
| } |
| |
| sos_screen_set_cursor (row, col); |
| |
| return SOS_OK; |
| } |
| |
| sos_ret_t sos_screen_init (void) |
| { |
| int i, j; |
| |
| row = CONSOLE_ROW_START; |
| col = 0; |
| |
| /* Set the first scan line for the cursor, and the blinking |
| mode. First scan line is 11, so that we have a visible |
| cursor. */ |
| outb(VGA_SET_CURSOR_START, VGA_COMMAND_PORT); |
| outb(((0x2 << 5) | 14), VGA_DATA_PORT); |
| |
| for (i = CONSOLE_ROW_START; i < LINES; i++) |
| { |
| for (j = 0; j < COLUMNS; j++) |
| sos_x86_videomem_putchar |
| (i, j, SOS_X86_VIDEO_FG_BLUE | SOS_X86_VIDEO_BG_LTGRAY, ' '); |
| } |
| |
| sos_screen_set_cursor (row, col); |
| |
| return SOS_OK; |
| } |
| |
/tmp/sos-code-article8/extra/patch-qemu-port-e9.diff (1970-01-01 01:00:00.000000000 +0100
) |
|
../sos-code-article9/extra/patch-qemu-port-e9.diff (2005-12-28 11:44:56.000000000 +0100
) |
|
|
|
| |
| Patch to enable the "port 0xe9" debugging facility in qemu (version |
| 0.7.2). This input/output port is used extensively in SOS to ease |
| debugging (the sos_bochs_printf family of functions). |
| |
| -- Thomas Petazzoni and Christophe Lucas |
| |
| |
| diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/hw/pc.c qemu-0.7.2-clucas/hw/pc.c |
| --- qemu-0.7.2/hw/pc.c 2005-09-04 19:11:31.000000000 +0200 |
| +++ qemu-0.7.2-clucas/hw/pc.c 2005-09-14 11:24:51.000000000 +0200 |
| @@ -620,6 +620,12 @@ static void pc_init1(int ram_size, int v |
| |
| cmos_init(ram_size, boot_device, bs_table); |
| |
| + for(i=0 ; i<MAX_PORT_E9_PORTS ; i++) { |
| + if (port_e9_hds[i]) { |
| + port_e9_init(port_e9_hds[i]); |
| + } |
| + } |
| + |
| /* must be done after all PCI devices are instanciated */ |
| /* XXX: should be done in the Bochs BIOS */ |
| if (pci_enabled) { |
| diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/Makefile.target qemu-0.7.2-clucas/Makefile.target |
| --- qemu-0.7.2/Makefile.target 2005-09-04 19:11:31.000000000 +0200 |
| +++ qemu-0.7.2-clucas/Makefile.target 2005-09-14 11:24:50.000000000 +0200 |
| @@ -286,7 +286,7 @@ endif |
| ifeq ($(TARGET_BASE_ARCH), i386) |
| # Hardware support |
| VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) |
| -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o |
| +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o port_e9.o |
| VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o |
| endif |
| ifeq ($(TARGET_BASE_ARCH), ppc) |
| diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/port_e9.c qemu-0.7.2-clucas/port_e9.c |
| --- qemu-0.7.2/port_e9.c 1970-01-01 01:00:00.000000000 +0100 |
| +++ qemu-0.7.2-clucas/port_e9.c 2005-09-14 11:24:51.000000000 +0200 |
| @@ -0,0 +1,51 @@ |
| +/* |
| + * QEMU Port 0xe9 hack |
| + * |
| + * Copyright (c) 2000-2004 E. Marty, the bochs team, D.Decotigny |
| + * |
| + * Permission is hereby granted, free of charge, to any person obtaining a copy |
| + * of this software and associated documentation files (the "Software"), to deal |
| + * in the Software without restriction, including without limitation the rights |
| + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| + * copies of the Software, and to permit persons to whom the Software is |
| + * furnished to do so, subject to the following conditions: |
| + * |
| + * The above copyright notice and this permission notice shall be included in |
| + * all copies or substantial portions of the Software. |
| + * |
| + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| + * THE SOFTWARE. |
| + */ |
| + |
| +#include <stdio.h> |
| +#include <unistd.h> |
| +#include <inttypes.h> |
| + |
| +#include "vl.h" |
| + |
| +static void port_e9_write(void *opaque, uint32_t address, uint32_t data) |
| +{ |
| + CharDriverState *chr; |
| + chr = opaque; |
| + |
| + qemu_chr_write(chr, & data, 1); |
| +} |
| + |
| +static uint32_t port_e9_read(void *opaque, uint32_t address) |
| +{ |
| + return 0xE9; |
| +} |
| + |
| +CharDriverState *port_e9_init (CharDriverState *chr) |
| +{ |
| + register_ioport_write(0xe9, 1, 1, port_e9_write, chr); |
| + register_ioport_read (0xe9, 1, 1, port_e9_read, chr); |
| + |
| + return chr; |
| +} |
| + |
| diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/vl.c qemu-0.7.2-clucas/vl.c |
| --- qemu-0.7.2/vl.c 2005-09-04 19:11:31.000000000 +0200 |
| +++ qemu-0.7.2-clucas/vl.c 2005-09-14 11:24:51.000000000 +0200 |
| @@ -146,6 +146,7 @@ int graphic_depth = 15; |
| int full_screen = 0; |
| TextConsole *vga_console; |
| CharDriverState *serial_hds[MAX_SERIAL_PORTS]; |
| +CharDriverState *port_e9_hds[MAX_PORT_E9_PORTS]; |
| CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; |
| #ifdef TARGET_I386 |
| int win2k_install_hack = 0; |
| @@ -2969,6 +2970,7 @@ enum { |
| QEMU_OPTION_monitor, |
| QEMU_OPTION_serial, |
| QEMU_OPTION_parallel, |
| + QEMU_OPTION_port_e9, |
| QEMU_OPTION_loadvm, |
| QEMU_OPTION_full_screen, |
| QEMU_OPTION_pidfile, |
| @@ -3040,6 +3042,7 @@ const QEMUOption qemu_options[] = { |
| { "monitor", 1, QEMU_OPTION_monitor }, |
| { "serial", 1, QEMU_OPTION_serial }, |
| { "parallel", 1, QEMU_OPTION_parallel }, |
| + { "port-e9", 1, QEMU_OPTION_port_e9 }, |
| { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, |
| { "full-screen", 0, QEMU_OPTION_full_screen }, |
| { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, |
| @@ -3143,6 +3146,8 @@ int main(int argc, char **argv) |
| char monitor_device[128]; |
| char serial_devices[MAX_SERIAL_PORTS][128]; |
| int serial_device_index; |
| + char port_e9_devices[MAX_PORT_E9_PORTS][128]; |
| + int port_e9_device_index; |
| char parallel_devices[MAX_PARALLEL_PORTS][128]; |
| int parallel_device_index; |
| const char *loadvm = NULL; |
| @@ -3184,12 +3189,17 @@ int main(int argc, char **argv) |
| for(i = 1; i < MAX_SERIAL_PORTS; i++) |
| serial_devices[i][0] = '\0'; |
| serial_device_index = 0; |
| - |
| + |
| pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc"); |
| for(i = 1; i < MAX_PARALLEL_PORTS; i++) |
| parallel_devices[i][0] = '\0'; |
| parallel_device_index = 0; |
| - |
| + |
| + pstrcpy(port_e9_devices[0], sizeof(port_e9_devices[0]), "vc"); |
| + for(i = 1; i < MAX_PORT_E9_PORTS; i++) |
| + port_e9_devices[i][0] = '\0'; |
| + port_e9_device_index = 0; |
| + |
| nb_tun_fds = 0; |
| net_if_type = -1; |
| nb_nics = 1; |
| @@ -3526,6 +3536,15 @@ int main(int argc, char **argv) |
| sizeof(parallel_devices[0]), optarg); |
| parallel_device_index++; |
| break; |
| + case QEMU_OPTION_port_e9: |
| + if (port_e9_device_index >= MAX_PORT_E9_PORTS) { |
| + fprintf(stderr, "qemu: too many port e9 ports\n"); |
| + exit(1); |
| + } |
| + pstrcpy(port_e9_devices[port_e9_device_index], |
| + sizeof(port_e9_devices[0]), optarg); |
| + port_e9_device_index++; |
| + break; |
| case QEMU_OPTION_loadvm: |
| loadvm = optarg; |
| break; |
| @@ -3771,6 +3790,19 @@ int main(int argc, char **argv) |
| } |
| } |
| |
| + for (i=0 ; i<MAX_PORT_E9_PORTS ; i++) { |
| + if (port_e9_devices[i][0] != '\0') { |
| + port_e9_hds[i] = qemu_chr_open(port_e9_devices[i]); |
| + if (!port_e9_hds[i]) { |
| + fprintf(stderr, "qemu: could not open port e9 device '%s'\n", |
| + port_e9_devices[i]); |
| + exit(1); |
| + } |
| + if (!strcmp(port_e9_devices[i], "vc")) |
| + qemu_chr_printf(port_e9_hds[i], "port_e9_%d console\n", i); |
| + } |
| + } |
| + |
| /* setup cpu signal handlers for MMU / self modifying code handling */ |
| #if !defined(CONFIG_SOFTMMU) |
| |
| diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/vl.h qemu-0.7.2-clucas/vl.h |
| --- qemu-0.7.2/vl.h 2005-09-04 19:11:31.000000000 +0200 |
| +++ qemu-0.7.2-clucas/vl.h 2005-09-14 11:24:51.000000000 +0200 |
| @@ -242,6 +242,15 @@ extern CharDriverState *serial_hds[MAX_S |
| |
| extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; |
| |
| +/* port E9 ports */ |
| +#define MAX_PORT_E9_PORTS 1 |
| + |
| +#if (MAX_PORT_E9_PORTS != 1) |
| + #error "No more than one port E9 is supported" |
| +#endif |
| + |
| +extern CharDriverState *port_e9_hds[MAX_PORT_E9_PORTS]; |
| + |
| /* network redirectors support */ |
| |
| #define MAX_NICS 8 |
| @@ -688,6 +697,9 @@ SerialState *serial_init(int base, int i |
| typedef struct ParallelState ParallelState; |
| ParallelState *parallel_init(int base, int irq, CharDriverState *chr); |
| |
| +/* port-e9.c */ |
| +CharDriverState *port_e9_init(CharDriverState *chr); |
| + |
| /* i8259.c */ |
| |
| typedef struct PicState2 PicState2; |
| |
/tmp/sos-code-article8/sos/chardev.c (1970-01-01 01:00:00.000000000 +0100
) |
|
../sos-code-article9/sos/chardev.c (2005-12-28 11:44:57.000000000 +0100
) |
|
|
|
| /* Copyright (C) 2005 David Decotigny, Thomas Petazzoni |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. |
| */ |
| |
| #include <sos/assert.h> |
| #include <sos/types.h> |
| #include <sos/fs.h> |
| #include <sos/list.h> |
| #include <sos/kmalloc.h> |
| |
| #include "chardev.h" |
| |
| struct sos_chardev_class |
| { |
| sos_ui32_t device_class; |
| struct sos_chardev_ops *ops; |
| |
| /** This corresponds to the chardev_class_custom_data field passed |
| to open/read/etc. and to sos_chardev_register_class() */ |
| void *custom_data; |
| |
| sos_count_t ref_cnt; /**< increased each time a FS |
| node is opened */ |
| |
| struct sos_chardev_class *next, *prev; |
| }; |
| |
| |
| struct sos_chardev_opened_file |
| { |
| /** "normal" VFS opened file structure is available in this |
| structure */ |
| struct sos_fs_opened_file super; |
| |
| /** Additional information for this opened file: the device's class |
| structure */ |
| struct sos_chardev_class *class; |
| }; |
| |
| |
| /** The list of registered classes, ie the dictionary major number -> |
| device class description */ |
| static struct sos_chardev_class *registered_chardev_classes; |
| |
| |
| /* Forward declarations */ |
| static struct sos_fs_ops_opened_file chardev_ops_opened_file; |
| static struct sos_fs_ops_opened_chardev chardev_ops_opened_chardev; |
| |
| static sos_ret_t |
| chardev_helper_sync(struct sos_fs_node * this); |
| static sos_ret_t |
| chardev_helper_new_opened_file(struct sos_fs_node * this, |
| const struct sos_process * owner, |
| sos_ui32_t open_flags, |
| struct sos_fs_opened_file ** result_of); |
| static sos_ret_t |
| chardev_helper_close_opened_file(struct sos_fs_node * this, |
| struct sos_fs_opened_file * of); |
| static sos_ret_t |
| duplicate_opened_chardev(struct sos_fs_opened_file *this, |
| const struct sos_process * for_owner, |
| struct sos_fs_opened_file **result); |
| |
| |
| /** |
| * Return the device descriptionn structure for the corresponding |
| * device class, or NULL when none found. |
| */ |
| static struct sos_chardev_class * lookup_chardev_class(sos_ui32_t device_class) |
| { |
| struct sos_chardev_class *chardev; |
| int nb; |
| |
| list_foreach (registered_chardev_classes, chardev, nb) |
| { |
| if (chardev->device_class == device_class) |
| return chardev; |
| } |
| |
| return NULL; |
| } |
| |
| |
| sos_ret_t sos_chardev_register_class (sos_ui32_t device_class, |
| struct sos_chardev_ops *ops, |
| void * chardev_class_custom_data) |
| { |
| struct sos_chardev_class *chardev; |
| |
| /* Make sure this device class is not already registered */ |
| chardev = lookup_chardev_class(device_class); |
| if (NULL != chardev) |
| return -SOS_EBUSY; |
| |
| /* Allocate and initialize a new device description */ |
| chardev = (struct sos_chardev_class *) |
| sos_kmalloc(sizeof(struct sos_chardev_class), 0); |
| if (chardev == NULL) |
| return -SOS_ENOMEM; |
| |
| chardev->device_class = device_class; |
| chardev->custom_data = chardev_class_custom_data; |
| chardev->ops = ops; |
| chardev->ref_cnt = 1; |
| |
| /* insert it into the list */ |
| list_add_tail (registered_chardev_classes, chardev); |
| |
| return SOS_OK; |
| } |
| |
| |
| sos_ret_t sos_chardev_unregister_class (sos_ui32_t device_class) |
| { |
| struct sos_chardev_class *chardev; |
| |
| /* Make sure this device class is already registered */ |
| chardev = lookup_chardev_class(device_class); |
| if (NULL == chardev) |
| return -SOS_ENODEV; |
| |
| /* Make sure no files are already opened for it */ |
| if (chardev->ref_cnt != 1) |
| return -SOS_EBUSY; |
| |
| /* remove it from the list */ |
| list_delete (registered_chardev_classes, chardev); |
| return sos_kfree((sos_vaddr_t)chardev); |
| } |
| |
| |
| |
| sos_ret_t sos_chardev_helper_ref_new_fsnode(struct sos_fs_node * this) |
| { |
| this->sync = chardev_helper_sync; |
| this->new_opened_file = chardev_helper_new_opened_file; |
| this->close_opened_file = chardev_helper_close_opened_file; |
| |
| return SOS_OK; |
| } |
| |
| |
| sos_ret_t sos_chardev_helper_release_fsnode(struct sos_fs_node * this) |
| { |
| return SOS_OK; |
| } |
| |
| |
| /** No synchronization to anything needed for a character device */ |
| static sos_ret_t |
| chardev_helper_sync(struct sos_fs_node * this) |
| { |
| return SOS_OK; |
| } |
| |
| |
| /** Callback called each time an FS-node is opened by a user process: |
| create a new sos_chardev_opened_file object associated to the |
| correct major number, and call the device driver's open method */ |
| static sos_ret_t |
| chardev_helper_new_opened_file(struct sos_fs_node * this, |
| const struct sos_process * owner, |
| sos_ui32_t open_flags, |
| struct sos_fs_opened_file ** result_of) |
| { |
| sos_ret_t retval; |
| struct sos_chardev_opened_file *chardev_of; |
| |
| /* Lookup the character device description structure */ |
| struct sos_chardev_class * chardev |
| = lookup_chardev_class(this->dev_id.device_class); |
| if (NULL == chardev) |
| return -SOS_ENODEV; |
| |
| /* Alloocate the new "open file" description structure */ |
| chardev_of = (struct sos_chardev_opened_file*) |
| sos_kmalloc(sizeof(struct sos_chardev_opened_file), 0); |
| if (NULL == chardev_of) |
| return -SOS_ENOMEM; |
| |
| memset(chardev_of, 0x0, sizeof(struct sos_chardev_opened_file)); |
| chardev_of->class = chardev; |
| *result_of = & chardev_of->super; |
| |
| /* Increase the reference coount for that node */ |
| SOS_ASSERT_FATAL(chardev->ref_cnt >= 1); |
| chardev->ref_cnt ++; |
| |
| /* Initialize the read/write/seek callbacks */ |
| (*result_of)->owner = owner; |
| (*result_of)->open_flags = open_flags; |
| (*result_of)->ops_file = & chardev_ops_opened_file; |
| (*result_of)->ops_chardev = & chardev_ops_opened_chardev; |
| |
| /* Call the open callback */ |
| retval = chardev->ops->open(this, & chardev_of->super, chardev->custom_data); |
| if (SOS_OK != retval) |
| { |
| sos_kfree((sos_vaddr_t) chardev_of); |
| chardev->ref_cnt --; |
| *result_of = NULL; |
| return retval; |
| } |
| |
| /* Specify the duplicate method */ |
| (*result_of)->duplicate = duplicate_opened_chardev; |
| |
| return retval; |
| } |
| |
| |
| /** Callback called each time an opened file is closed. Un-allocate |
| the associated sos_chardev_opened_file object */ |
| static sos_ret_t |
| chardev_helper_close_opened_file(struct sos_fs_node * this, |
| struct sos_fs_opened_file * of) |
| { |
| sos_ret_t retval; |
| struct sos_chardev_opened_file *chardev_of |
| = ((struct sos_chardev_opened_file*)of); |
| |
| struct sos_chardev_class * chardev = chardev_of->class; |
| SOS_ASSERT_FATAL(NULL != chardev); |
| |
| /* Free the new "open file" description structure */ |
| if (NULL != chardev->ops->close) |
| retval = chardev->ops->close(& chardev_of->super, chardev->custom_data); |
| else |
| retval = SOS_OK; |
| if (SOS_OK != retval) |
| return retval; |
| |
| /* Decrease the reference coount for that node */ |
| SOS_ASSERT_FATAL(chardev->ref_cnt > 1); |
| chardev->ref_cnt --; |
| |
| sos_kfree((sos_vaddr_t) chardev_of); |
| return retval; |
| } |
| |
| |
| /** |
| * Callback called each time a process is "forked": create a new |
| * sos_chardev_opened_file for the new process. |
| * |
| * @note Almost identical to the open callback. |
| */ |
| static sos_ret_t |
| duplicate_opened_chardev(struct sos_fs_opened_file *this, |
| const struct sos_process * for_owner, |
| struct sos_fs_opened_file **result) |
| { |
| sos_ret_t retval; |
| struct sos_chardev_opened_file *chardev_of |
| = ((struct sos_chardev_opened_file*)this); |
| struct sos_chardev_opened_file *new_chardev_of; |
| struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry); |
| |
| *result = NULL; |
| |
| /* Lookup the character device description structure */ |
| struct sos_chardev_class * chardev = chardev_of->class; |
| SOS_ASSERT_FATAL(NULL != chardev); |
| |
| /* Allocate a new duplicate copy of the original opened file */ |
| new_chardev_of = (struct sos_chardev_opened_file*) |
| sos_kmalloc(sizeof(struct sos_chardev_opened_file), 0); |
| if (NULL == new_chardev_of) |
| return -SOS_ENOMEM; |
| |
| memcpy(new_chardev_of, chardev_of, sizeof(*new_chardev_of)); |
| new_chardev_of->super.owner = for_owner; |
| new_chardev_of->super.direntry = NULL; /* Reset the direntry |
| for the new opened file */ |
| SOS_ASSERT_FATAL(chardev->ref_cnt > 1); |
| chardev->ref_cnt ++; |
| |
| retval = chardev->ops->open(fsnode, |
| & new_chardev_of->super, chardev->custom_data); |
| if (SOS_OK != retval) |
| { |
| sos_kfree((sos_vaddr_t) new_chardev_of); |
| chardev->ref_cnt --; |
| return retval; |
| } |
| |
| /* Make sure the required methods are overloaded */ |
| SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file); |
| SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file->seek); |
| SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file->read); |
| |
| *result = & new_chardev_of->super; |
| return retval; |
| } |
| |
| |
| /* |
| * FS generic character device wrapper functions |
| */ |
| |
| /** |
| * Callback called to change the position in the opened file: call the |
| * seek method of the device driver. |
| */ |
| static sos_ret_t chardev_wrap_seek(struct sos_fs_opened_file *this, |
| sos_lsoffset_t offset, |
| sos_seek_whence_t whence, |
| /* out */ sos_lsoffset_t * result_position) |
| { |
| sos_ret_t retval = -SOS_ENOSYS; |
| struct sos_chardev_opened_file *chardev_of |
| = ((struct sos_chardev_opened_file*)this); |
| |
| struct sos_chardev_class * chardev = chardev_of->class; |
| SOS_ASSERT_FATAL(NULL != chardev); |
| SOS_ASSERT_FATAL(NULL != chardev->ops); |
| |
| if (NULL != chardev->ops->seek) |
| retval = chardev->ops->seek(this, offset, whence, result_position); |
| |
| return retval; |
| } |
| |
| |
| /** |
| * Callback called to read the contents of the opened file: call the |
| * read method of the device driver. |
| */ |
| static sos_ret_t chardev_wrap_read(struct sos_fs_opened_file *this, |
| sos_uaddr_t dest_buf, |
| sos_size_t * /* in/out */len) |
| { |
| sos_ret_t retval = -SOS_ENOSYS; |
| struct sos_chardev_opened_file *chardev_of |
| = ((struct sos_chardev_opened_file*)this); |
| |
| struct sos_chardev_class * chardev = chardev_of->class; |
| SOS_ASSERT_FATAL(NULL != chardev); |
| SOS_ASSERT_FATAL(NULL != chardev->ops); |
| |
| if (NULL != chardev->ops->read) |
| retval = chardev->ops->read(this, dest_buf, len); |
| |
| return retval; |
| } |
| |
| |
| /** |
| * Callback called to write bytes to the opened file: call the write |
| * method of the device driver. |
| */ |
| static sos_ret_t chardev_wrap_write(struct sos_fs_opened_file *this, |
| sos_uaddr_t src_buf, |
| sos_size_t * /* in/out */len) |
| { |
| sos_ret_t retval = -SOS_ENOSYS; |
| struct sos_chardev_opened_file *chardev_of |
| = ((struct sos_chardev_opened_file*)this); |
| |
| struct sos_chardev_class * chardev = chardev_of->class; |
| SOS_ASSERT_FATAL(NULL != chardev); |
| SOS_ASSERT_FATAL(NULL != chardev->ops); |
| |
| if (NULL != chardev->ops->write) |
| retval = chardev->ops->write(this, src_buf, len); |
| |
| return retval; |
| } |
| |
| |
| /** |
| * Callback called to map the contents of the opened file: call the |
| * map method of the device driver. |
| */ |
| static sos_ret_t chardev_wrap_mmap(struct sos_fs_opened_file *this, |
| sos_uaddr_t *uaddr, sos_size_t size, |
| sos_ui32_t access_rights, |
| sos_ui32_t flags, |
| sos_luoffset_t offset) |
| { |
| sos_ret_t retval = -SOS_ENOSYS; |
| struct sos_chardev_opened_file *chardev_of |
| = ((struct sos_chardev_opened_file*)this); |
| |
| struct sos_chardev_class * chardev = chardev_of->class; |
| SOS_ASSERT_FATAL(NULL != chardev); |
| SOS_ASSERT_FATAL(NULL != chardev->ops); |
| |
| if (NULL != chardev->ops->mmap) |
| retval = chardev->ops->mmap(this, uaddr, size, |
| access_rights, flags, offset); |
| |
| return retval; |
| } |
| |
| |
| /** |
| * Callback called to change the state of the opened file: call the |
| * fcntl method of the device driver. |
| */ |
| static sos_ret_t chardev_wrap_fcntl(struct sos_fs_opened_file *this, |
| int req_id, |
| sos_ui32_t req_arg) |
| { |
| sos_ret_t retval = -SOS_ENOSYS; |
| struct sos_chardev_opened_file *chardev_of |
| = ((struct sos_chardev_opened_file*)this); |
| |
| struct sos_chardev_class * chardev = chardev_of->class; |
| SOS_ASSERT_FATAL(NULL != chardev); |
| SOS_ASSERT_FATAL(NULL != chardev->ops); |
| |
| if (NULL != chardev->ops->fcntl) |
| retval = chardev->ops->fcntl(this, req_id, req_arg); |
| |
| return retval; |
| } |
| |
| |
| /** |
| * Callback called to control the underlying device: call the ioctl |
| * method of the device driver. |
| */ |
| static sos_ret_t chardev_wrap_ioctl(struct sos_fs_opened_file *this, |
| int req_id, |
| sos_ui32_t req_arg) |
| { |
| sos_ret_t retval = -SOS_ENOSYS; |
| struct sos_chardev_opened_file *chardev_of |
| = ((struct sos_chardev_opened_file*)this); |
| |
| struct sos_chardev_class * chardev = chardev_of->class; |
| SOS_ASSERT_FATAL(NULL != chardev); |
| SOS_ASSERT_FATAL(NULL != chardev->ops); |
| |
| if (NULL != chardev->ops->ioctl) |
| retval = chardev->ops->ioctl(this, req_id, req_arg); |
| |
| return retval; |
| } |
| |
| |
| /** |
| * Gather the callbacks for a "character device" opened file |
| */ |
| static struct sos_fs_ops_opened_file chardev_ops_opened_file |
| = (struct sos_fs_ops_opened_file) { |
| .seek = chardev_wrap_seek, |
| .read = chardev_wrap_read, |
| .write = chardev_wrap_write, |
| .mmap = chardev_wrap_mmap, |
| .fcntl = chardev_wrap_fcntl |
| }; |
| |
| |
| static struct sos_fs_ops_opened_chardev chardev_ops_opened_chardev |
| = (struct sos_fs_ops_opened_chardev) { |
| .ioctl = chardev_wrap_ioctl |
| }; |
| |
/tmp/sos-code-article8/sos/fs.c (2005-07-01 16:39:49.000000000 +0200
) |
|
../sos-code-article9/sos/fs.c (2005-12-28 11:44:57.000000000 +0100
) |
|
|
|
#include <sos/list.h> | #include <sos/list.h> |
#include <sos/kmem_slab.h> | #include <sos/kmem_slab.h> |
#include <sos/kmalloc.h> | #include <sos/kmalloc.h> |
| #include "chardev.h" |
| |
#include "fs.h" | #include "fs.h" |
| |
|
|
* Basic low-level memory & co related functions | * Basic low-level memory & co related functions |
*/ | */ |
| |
sos_ret_t sos_fs_subsystem_setup(const char * root_device, | sos_ret_t |
const char * fsname, | sos_fs_subsystem_setup(const char * root_device, |
const char * mount_args, | const char * fsname, |
struct sos_fs_manager_instance ** result_rootfs) | const char * mount_args, |
| struct sos_fs_manager_instance ** result_rootfs) |
sos_ret_t retval; | sos_ret_t retval; |
struct sos_fs_manager_type * fs_type; | struct sos_fs_manager_type * fs_type; |
|
|
| |
if (node->inmem_ref_cnt == 0) | if (node->inmem_ref_cnt == 0) |
{ | { |
| if (SOS_FS_NODE_DEVICE_CHAR == node->type) |
| sos_chardev_helper_release_fsnode(node); |
sos_hash_remove(node->fs->nodecache, node); | sos_hash_remove(node->fs->nodecache, node); |
node->destructor(node); | node->destructor(node); |
} | } |
|
|
return retval; | return retval; |
| |
(*result_fsnode)->generation = 0; | (*result_fsnode)->generation = 0; |
| |
| /* Special case for device nodes */ |
| if (SOS_FS_NODE_DEVICE_CHAR == (*result_fsnode)->type) |
| SOS_ASSERT_FATAL(SOS_OK |
| == sos_chardev_helper_ref_new_fsnode(*result_fsnode)); |
sos_hash_insert(fs->nodecache, *result_fsnode); | sos_hash_insert(fs->nodecache, *result_fsnode); |
return SOS_OK; | return SOS_OK; |
} | } |
|
|
/* Update some resrved fields */ | /* Update some resrved fields */ |
(*result_fsnode)->fs = fs; | (*result_fsnode)->fs = fs; |
| |
| /* Special case for device nodes */ |
| if (SOS_FS_NODE_DEVICE_CHAR == (*result_fsnode)->type) |
| { |
| SOS_ASSERT_FATAL(SOS_OK |
| == sos_chardev_helper_ref_new_fsnode(*result_fsnode)); |
| } |
| |
/* insert it in the node cache */ | /* insert it in the node cache */ |
retval = sos_hash_insert(fs->nodecache, *result_fsnode); | retval = sos_hash_insert(fs->nodecache, *result_fsnode); |
if (SOS_OK != retval) | if (SOS_OK != retval) |
|
|
{ | { |
/* Commit the FS changes to the device */ | /* Commit the FS changes to the device */ |
if (SOS_OK | if (SOS_OK |
== fsnode->fs->device->ops_file->sync(fsnode->fs->device)) | == fsnode->fs->device->sync(fsnode->fs->device)) |
| |
/* We got a problem: FORCE re-add the node to the dirty list */ | /* We got a problem: FORCE re-add the node to the dirty list */ |
|
|
if (! fsnode->dirty) | if (! fsnode->dirty) |
return SOS_OK; | return SOS_OK; |
| |
retval = fsnode->ops_file->sync(fsnode); | retval = fsnode->sync(fsnode); |
return retval; | return retval; |
| |
|
|
} | } |
| |
if (NULL != fs->device) | if (NULL != fs->device) |
return fs->device->ops_file->sync(fs->device); | return fs->device->sync(fs->device); |
return SOS_OK; | return SOS_OK; |
} | } |
|
|
| |
retval = fsnode->new_opened_file(fsnode, owner, open_flags, result_of); | retval = fsnode->new_opened_file(fsnode, owner, open_flags, result_of); |
if (SOS_OK != retval) | if (SOS_OK != retval) |
{ | |
sos_fs_nscache_unref_node(nsnode); | |
} | |
(*result_of)->generation = 1; | (*result_of)->generation = 1; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
return retval; | return retval; |
| |
| SOS_ASSERT_FATAL((*result_of)->owner == dst_proc); |
(*result_of)->ref_cnt = 1; | (*result_of)->ref_cnt = 1; |
(*result_of)->generation = 1; | (*result_of)->generation = 1; |
retval = sos_fs_nscache_register_opened_file(src_of->direntry, *result_of); | retval = sos_fs_nscache_register_opened_file(src_of->direntry, *result_of); |
|
|
struct sos_fs_pathname path; | struct sos_fs_pathname path; |
| |
/* O_DIR | O_CREAT combination not supported */ | /* O_DIR | O_CREAT combination not supported */ |
if ((open_flags & SOS_FS_OPEN_DIRECTORY) | if ( (open_flags & SOS_FS_OPEN_DIRECTORY) |
&& (open_flags & SOS_FS_OPEN_CREAT)) | && ( (open_flags & (SOS_FS_OPEN_CREAT |
| | SOS_FS_OPEN_TRUNC)) ) ) |
| |
if (_pathlen <= 0) | if (_pathlen <= 0) |
|
|
if (path.length <= 0) | if (path.length <= 0) |
{ | { |
/* Found the exact match ! */ | /* Found the exact match ! */ |
| |
| /* Handle O_EXCL flag */ |
if (open_flags & SOS_FS_OPEN_EXCL) | if (open_flags & SOS_FS_OPEN_EXCL) |
{ | { |
sos_fs_nscache_unref_node(nsnode); | sos_fs_nscache_unref_node(nsnode); |
|
|
sos_fs_nscache_unref_node(nsnode); | sos_fs_nscache_unref_node(nsnode); |
return -SOS_ENOTDIR; | return -SOS_ENOTDIR; |
} | } |
| |
| /* Handle O_TRUNC flag */ |
| if ((open_flags & SOS_FS_OPEN_TRUNC) |
| && fsnode->ops_file->truncate) |
| { |
| retval = fsnode->ops_file->truncate(fsnode, 0); |
| if (SOS_OK != retval) |
| { |
| sos_fs_nscache_unref_node(nsnode); |
| return retval; |
| } |
| } |
} | } |
else | else |
{ | { |
|
|
return -SOS_EPERM; | return -SOS_EPERM; |
| |
if (! of->ops_file->read) | if (! of->ops_file->read) |
return -SOS_ENOSUP; | return -SOS_ENOSYS; |
return of->ops_file->read(of, dest_buf, len); | return of->ops_file->read(of, dest_buf, len); |
} | } |
|
|
sos_uaddr_t src_buf, | sos_uaddr_t src_buf, |
sos_size_t * /* in/out */len) | sos_size_t * /* in/out */len) |
{ | { |
if (! (of->open_flags & SOS_FS_OPEN_WRITE)) | if (! (of->open_flags & SOS_FS_OPEN_WRITE)) |
return -SOS_EPERM; | return -SOS_EPERM; |
if (! of->ops_file->write) | if (! of->ops_file->write) |
return -SOS_ENOSUP; | return -SOS_ENOSYS; |
return of->ops_file->write(of, src_buf, len); | return of->ops_file->write(of, src_buf, len); |
} | } |
|
|
sos_lsoffset_t * result_position) | sos_lsoffset_t * result_position) |
{ | { |
if (! of->ops_file->seek) | if (! of->ops_file->seek) |
return -SOS_ENOSUP; | return -SOS_ENOSYS; |
return of->ops_file->seek(of, offset, whence, result_position); | return of->ops_file->seek(of, offset, whence, result_position); |
} | } |
|
|
return -SOS_EPERM; | return -SOS_EPERM; |
| |
if (! fsnode->ops_file->truncate) | if (! fsnode->ops_file->truncate) |
return -SOS_ENOSUP; | return -SOS_ENOSYS; |
retval = fsnode->ops_file->truncate(fsnode, length); | retval = fsnode->ops_file->truncate(fsnode, length); |
if (SOS_OK == retval) | if (SOS_OK == retval) |
|
|
struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry); | struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry); |
| |
if (! of->ops_file->mmap) | if (! of->ops_file->mmap) |
return -SOS_ENOSUP; | return -SOS_ENOSYS; |
/* Translate VM requested rights into FS equivalent */ | /* Translate VM requested rights into FS equivalent */ |
if (access_rights & SOS_VM_MAP_PROT_READ) | if (access_rights & SOS_VM_MAP_PROT_READ) |
|
|
sos_ui32_t req_arg /* Usually: sos_uaddr_t */) | sos_ui32_t req_arg /* Usually: sos_uaddr_t */) |
{ | { |
if (! of->ops_file->fcntl) | if (! of->ops_file->fcntl) |
return -SOS_ENOSUP; | return -SOS_ENOSYS; |
return of->ops_file->fcntl(of, req_id, req_arg); | return of->ops_file->fcntl(of, req_id, req_arg); |
} | } |
| |
| |
| sos_ret_t sos_fs_ioctl(struct sos_fs_opened_file *of, |
| int req_id, |
| sos_ui32_t req_arg /* Usually: sos_uaddr_t */) |
| { |
| struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry); |
| |
| if (fsnode->type == SOS_FS_NODE_DEVICE_CHAR) |
| { |
| if (! of->ops_chardev->ioctl) |
| return -SOS_ENOSYS; |
| |
| return of->ops_chardev->ioctl(of, req_id, req_arg); |
| } |
| |
| return -SOS_ENOSYS; |
| } |
| |
| |
sos_ret_t sos_fs_readdir(struct sos_fs_opened_file * of, | sos_ret_t sos_fs_readdir(struct sos_fs_opened_file * of, |
struct sos_fs_dirent * result) | struct sos_fs_dirent * result) |
{ | { |
|
|
} | } |
| |
| |
| sos_ret_t sos_fs_mknod(const struct sos_process * creator, |
| const char * _path, |
| sos_size_t _pathlen, |
| sos_fs_node_type_t type /* only block/char allowed */, |
| sos_ui32_t access_rights, |
| const struct sos_fs_dev_id_t * devid) |
| { |
| sos_ret_t retval; |
| struct sos_fs_pathname path; |
| struct sos_fs_nscache_node * nsnode; |
| struct sos_fs_node * fsnode; |
| |
| if (type != SOS_FS_NODE_DEVICE_CHAR) |
| return -SOS_EINVAL; |
| |
| path.contents = _path; |
| path.length = _pathlen; |
| |
| retval = fs_create_node(& path, creator, access_rights, |
| type, & nsnode); |
| if (SOS_OK != retval) |
| return retval; |
| |
| fsnode = sos_fs_nscache_get_fs_node(nsnode); |
| fsnode->dev_id.device_class = devid->device_class; |
| fsnode->dev_id.device_instance = devid->device_instance; |
| |
| sos_fs_nscache_unref_node(nsnode); |
| return SOS_OK; |
| } |
| |
| |
sos_ret_t sos_fs_stat(const struct sos_process * actor, | sos_ret_t sos_fs_stat(const struct sos_process * actor, |
const char * _path, | const char * _path, |
sos_size_t _pathlen, | sos_size_t _pathlen, |
|
|
sos_ret_t sos_fs_fsync(struct sos_fs_opened_file * of) | sos_ret_t sos_fs_fsync(struct sos_fs_opened_file * of) |
{ | { |
struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry); | struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry); |
return fsnode->ops_file->sync(fsnode); | return fsnode->sync(fsnode); |
| |
| |
|
|
if (fsnode->fs->statfs) | if (fsnode->fs->statfs) |
retval = fsnode->fs->statfs(fsnode->fs, result); | retval = fsnode->fs->statfs(fsnode->fs, result); |
else | else |
retval = -SOS_ENOSUP; | retval = -SOS_ENOSYS; |
sos_fs_nscache_unref_node(nsnode); | sos_fs_nscache_unref_node(nsnode); |
return retval; | return retval; |
| |
/tmp/sos-code-article8/sos/fs.h (2005-07-01 16:39:49.000000000 +0200
) |
|
../sos-code-article9/sos/fs.h (2005-12-28 11:44:57.000000000 +0100
) |
|
|
|
* ========= | * ========= |
* The VFS layer is based on 3 central concepts: | * The VFS layer is based on 3 central concepts: |
* | * |
* - The meta-information for each file stored on disk (struct | * - The meta-information for each file stored on disk: size, |
* sos_fs_node for SOS, inode for Unix) | * permissions, ... (struct sos_fs_node for SOS, inode for Unix) |
* It is sufficient to know where this meta-information is located | * It is sufficient to know where this meta-information is located |
* on disk (a simple sector number most of the time) to build the | * on disk (a simple sector number most of the time) to build the |
|
|
* data of the file from the disk | * data of the file from the disk |
* | * |
* For example, consider that we know a sector that holds the meta | * For example, consider that we know a sector that holds the meta |
* information (ie size, permissions) is located at sector 64589 on | * information is located at sector 64589 on disk. By retrieving |
* disk. By retrieving this meta information directly from disk, we | * this meta information directly from disk, we can build the |
* can build the struct sos_fs_node, which would (for example) tell | * struct sos_fs_node, which would (for example) tell that the |
* that the corresponding file spans (for example) over sectors | * corresponding file spans (for example) over sectors 4345, 5645, |
* 4345, 5645, 4539 and 6575, is 1.7kB long | * 4539 and 6575, is 1.7kB long |
* Everything is stored this way on the disk, even the | * Everything is stored this way on the disk, even the |
* directories. From the disk contents' point of view, a directory | * directories. From the disk contents' point of view, a directory |
|
|
SOS_FS_NODE_REGULAR_FILE = 0x42, | SOS_FS_NODE_REGULAR_FILE = 0x42, |
SOS_FS_NODE_DIRECTORY = 0x24, | SOS_FS_NODE_DIRECTORY = 0x24, |
SOS_FS_NODE_SYMLINK = 0x84, | SOS_FS_NODE_SYMLINK = 0x84, |
| SOS_FS_NODE_DEVICE_CHAR = 0x48, |
} sos_fs_node_type_t; | } sos_fs_node_type_t; |
| |
| |
|
|
| |
| |
/** | /** |
* Data related to a particular "mounting" of a file system. A so-called "superblock" under Linux | * Data related to a particular "mounting" of a file system. A |
| * so-called "superblock" under Linux |
* This holds the FUNDAMENTAL functions responsible for loading struct | * This holds the FUNDAMENTAL functions responsible for loading struct |
* sos_fs_node from disk, or for allocating thom on disk. It also | * sos_fs_node from disk, or for allocating thom on disk. It also |
|
|
*/ | */ |
sos_lcount_t generation; | sos_lcount_t generation; |
| |
| /** |
| * @note Available only for device files (char/block) |
| * @note Publicly readable. Written only by |
| * sos_fs_manager_instance::fetch_node_from_disk() and mknod() |
| */ |
| struct sos_fs_dev_id_t |
| { |
| sos_ui32_t device_class; /**< aka "major" */ |
| sos_ui32_t device_instance; /**< aka "minor" */ |
| } dev_id; |
| |
/** Operations common to all node types */ | /** Operations common to all node types */ |
struct sos_fs_node_ops_file *ops_file; | struct sos_fs_node_ops_file *ops_file; |
| |
|
|
| |
| |
/** | /** |
| * Flush any change to disk |
| * |
| * @note Mandatory, may block. Appropriate locking MUST be implemented |
| */ |
| sos_ret_t (*sync)(struct sos_fs_node *this); |
| |
| |
| /** |
* Simply free this FS node from the kernel memory: it does NOT | * Simply free this FS node from the kernel memory: it does NOT |
* mean that the corresponding on-disk node is free ! Actually, the | * mean that the corresponding on-disk node is free ! Actually, the |
* corresponding ON-DISK node is free iff ondisk_lnk_cnt == 0. No | * corresponding ON-DISK node is free iff ondisk_lnk_cnt == 0. No |
|
|
* Called when a process opens the node | * Called when a process opens the node |
* | * |
* @note Mandatory, may block. Appropriate locking MUST be implemented | * @note Mandatory, may block. Appropriate locking MUST be implemented |
| * @note FS-specific EXCPET for device special files (char & |
| * block) because they are handled in an uniform way by the |
| * chardev/blockdev subsystems |
| * @note As a consequence, FS code can safely assume that "this" is |
| * never a character or block device |
*/ | */ |
sos_ret_t (*new_opened_file)(struct sos_fs_node * this, | sos_ret_t (*new_opened_file)(struct sos_fs_node * this, |
const struct sos_process * owner, | const struct sos_process * owner, |
|
|
* Called when a process opens the node | * Called when a process opens the node |
* | * |
* @note Mandatory, may block. Appropriate locking MUST be implemented | * @note Mandatory, may block. Appropriate locking MUST be implemented |
| * @note FS-specific EXCEPT for device special files (char & |
| * block) because they are handled in an uniform way by the |
| * chardev/blockdev subsystems |
| * @note As a consequence, FS code can safely assume that "this" is |
| * never a character or block device |
*/ | */ |
sos_ret_t (*close_opened_file)(struct sos_fs_node * this, | sos_ret_t (*close_opened_file)(struct sos_fs_node * this, |
struct sos_fs_opened_file * of); | struct sos_fs_opened_file * of); |
|
|
struct sos_fs_stat * result); | struct sos_fs_stat * result); |
| |
/** | /** |
* Flush any change to disk | |
* | |
* @note Mandatory, may block. Appropriate locking MUST be implemented | |
*/ | |
sos_ret_t (*sync)(struct sos_fs_node *this); | |
| |
/** | |
* | * |
* @note Mandatory, may block. Appropriate locking MUST be implemented | * @note Mandatory, may block. Appropriate locking MUST be implemented |
|
|
{ | { |
/** when direntry->fs_node->type == SOS_FS_NODE_DIRECTORY */ | /** when direntry->fs_node->type == SOS_FS_NODE_DIRECTORY */ |
struct sos_fs_ops_opened_dir * ops_dir; | struct sos_fs_ops_opened_dir * ops_dir; |
| |
| /** when direntry->fs_node->type == SOS_FS_NODE_DEVICE_CHAR */ |
| struct sos_fs_ops_opened_chardev * ops_chardev; |
}; /* Anonymous union (gcc extension) */ | }; /* Anonymous union (gcc extension) */ |
| |
/** | /** |
* Called upon fork() to duplicate all the opened files | * Called upon fork() to duplicate all the opened files |
| * |
| * @note FS-specific EXCEPT for device special files (char & |
| * block) because they are handled in an uniform way by the |
| * chardev/blockdev subsystems |
| * @note As a consequence, FS code can safely assume that "this" is |
| * never a character or block device |
*/ | */ |
sos_ret_t (*duplicate)(struct sos_fs_opened_file *this, | sos_ret_t (*duplicate)(struct sos_fs_opened_file *this, |
const struct sos_process * for_owner, | const struct sos_process * for_owner, |
|
|
}; | }; |
| |
| |
| /** |
| * The list of methods implementing the basic VFS opened character device |
| * operations |
| * |
| * @see sos_fs_opened_file::ops_file |
| */ |
| struct sos_fs_ops_opened_chardev |
| { |
| /** |
| * @note Optional (might be NULL), may block. Appropriate locking |
| * MUST be implemented |
| * @note Please call sos_fs_mark_dirty() if disk contents is changed |
| */ |
| sos_ret_t (*ioctl)(struct sos_fs_opened_file *this, |
| int req_id, |
| sos_ui32_t req_arg /* Usually: sos_uaddr_t */); |
| }; |
| |
| |
/** Data structure that is to be filled by readdir */ | /** Data structure that is to be filled by readdir */ |
struct sos_fs_dirent | struct sos_fs_dirent |
{ | { |
|
|
*/ | */ |
struct sos_fs_stat | struct sos_fs_stat |
{ | { |
| struct sos_fs_dev_id_t st_rdev; |
sos_fs_node_type_t st_type; | sos_fs_node_type_t st_type; |
sos_ui64_t st_storage_location; | sos_ui64_t st_storage_location; |
sos_ui32_t st_access_rights; | sos_ui32_t st_access_rights; |
|
|
*/ | */ |
struct sos_fs_statfs | struct sos_fs_statfs |
{ | { |
| struct sos_fs_dev_id_t f_rdev; |
sos_size_t f_sz_total; /**< Total size */ | sos_size_t f_sz_total; /**< Total size */ |
sos_size_t f_sz_free; /**< Size left on device */ | sos_size_t f_sz_free; /**< Size left on device */ |
sos_count_t f_node_total;/**< Total allocatable FS nodes */ | sos_count_t f_node_total;/**< Total allocatable FS nodes */ |
|
|
sos_ret_t sos_fs_sync_all_fs(); | sos_ret_t sos_fs_sync_all_fs(); |
| |
/** | /** |
* Retrieve filesystem status, or return -SOS_ENOSUP if filesystem | * Retrieve filesystem status, or return -SOS_ENOSYS if filesystem |
*/ | */ |
sos_ret_t sos_fs_vfstat(const struct sos_process * actor, | sos_ret_t sos_fs_vfstat(const struct sos_process * actor, |
|
|
*/ | */ |
#define SOS_FS_OPEN_EXCL (1 << 0) | #define SOS_FS_OPEN_EXCL (1 << 0) |
#define SOS_FS_OPEN_CREAT (1 << 1) | #define SOS_FS_OPEN_CREAT (1 << 1) |
#define SOS_FS_OPEN_NOFOLLOW (1 << 2) | #define SOS_FS_OPEN_TRUNC (1 << 2) |
#define SOS_FS_OPEN_DIRECTORY (1 << 3) /* Incompatible with CREAT */ | #define SOS_FS_OPEN_NOFOLLOW (1 << 3) |
#define SOS_FS_OPEN_SYNC (1 << 4) | #define SOS_FS_OPEN_DIRECTORY (1 << 4) /* Incompatible with CREAT/TRUNC */ |
#define SOS_FS_OPEN_KEEPONEXEC (1 << 5) /* By default, files are closed | #define SOS_FS_OPEN_SYNC (1 << 5) |
upon an exec() */ | #define SOS_FS_OPEN_CLOSEONEXEC (1 << 6) /* By default, files are kept |
| open upon an exec() */ |
#define SOS_FS_OPEN_READ (1 << 16) | #define SOS_FS_OPEN_READ (1 << 16) |
#define SOS_FS_OPEN_WRITE (1 << 17) | #define SOS_FS_OPEN_WRITE (1 << 17) |
|
|
int req_id, | int req_id, |
sos_ui32_t req_arg /* Usually: sos_uaddr_t */); | sos_ui32_t req_arg /* Usually: sos_uaddr_t */); |
| |
| sos_ret_t sos_fs_ioctl(struct sos_fs_opened_file *of, |
| int req_id, |
| sos_ui32_t req_arg /* Usually: sos_uaddr_t */); |
| |
sos_ret_t sos_fs_creat(const struct sos_process * creator, | sos_ret_t sos_fs_creat(const struct sos_process * creator, |
const char * _path, | const char * _path, |
sos_size_t _pathlen, | sos_size_t _pathlen, |
|
|
sos_uaddr_t symlink_target, | sos_uaddr_t symlink_target, |
sos_size_t symlink_target_len); | sos_size_t symlink_target_len); |
| |
| sos_ret_t sos_fs_mknod(const struct sos_process * creator, |
| const char * _path, |
| sos_size_t _pathlen, |
| sos_fs_node_type_t type /* only block/char allowed */, |
| sos_ui32_t access_rights, |
| const struct sos_fs_dev_id_t * devid); |
| |
sos_ret_t sos_fs_mkdir(const struct sos_process * creator, | sos_ret_t sos_fs_mkdir(const struct sos_process * creator, |
const char * _path, | const char * _path, |
sos_size_t _pathlen, | sos_size_t _pathlen, |
| |
/tmp/sos-code-article8/sos/main.c (2005-07-01 16:39:49.000000000 +0200
) |
|
../sos-code-article9/sos/main.c (2005-12-28 11:44:57.000000000 +0100
) |
|
|
|
#include <drivers/zero.h> | #include <drivers/zero.h> |
#include <sos/fs.h> | #include <sos/fs.h> |
#include <drivers/fs_virtfs.h> | #include <drivers/fs_virtfs.h> |
| #include <drivers/devices.h> |
| #include <drivers/mem.h> |
| #include <drivers/tty.h> |
| #include <drivers/console.h> |
| #include <drivers/serial.h> |
| |
/* Helper function to display each bits of a 32bits integer on the | /* Helper function to display each bits of a 32bits integer on the |
screen as dark or light carrets */ | screen as dark or light carrets */ |
|
|
/* ====================================================================== | /* ====================================================================== |
* Kernel thread showing some CPU usage statistics on the console every 1s | * Kernel thread showing some CPU usage statistics on the console every 1s |
*/ | */ |
| #define LOAD_DISPLAY_BASELINE 4 |
| #define LOAD_DISPLAY_STARTROW 34 |
static void stat_thread() | static void stat_thread() |
{ | { |
while (1) | while (1) |
|
|
sos_load_to_string(str1, load1); | sos_load_to_string(str1, load1); |
sos_load_to_string(str5, load5); | sos_load_to_string(str5, load5); |
sos_load_to_string(str15, load15); | sos_load_to_string(str15, load15); |
sos_x86_videomem_printf(16, 34, | sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+0, LOAD_DISPLAY_STARTROW, |
"Kernel (- Idle): %s %s %s ", | "Kernel (- Idle): %s %s %s ", |
str1, str5, str15); | str1, str5, str15); |
|
|
sos_load_to_string(str1, load1); | sos_load_to_string(str1, load1); |
sos_load_to_string(str5, load5); | sos_load_to_string(str5, load5); |
sos_load_to_string(str15, load15); | sos_load_to_string(str15, load15); |
sos_x86_videomem_printf(17, 34, | sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+1, LOAD_DISPLAY_STARTROW, |
"User: %s %s %s ", | "User: %s %s %s ", |
str1, str5, str15); | str1, str5, str15); |
|
|
sos_load_to_string(str1, load1); | sos_load_to_string(str1, load1); |
sos_load_to_string(str5, load5); | sos_load_to_string(str5, load5); |
sos_load_to_string(str15, load15); | sos_load_to_string(str15, load15); |
sos_x86_videomem_printf(18, 34, | sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+2, LOAD_DISPLAY_STARTROW, |
"User CPU %%: %s %s %s ", | "User CPU %%: %s %s %s ", |
str1, str5, str15); | str1, str5, str15); |
|
|
sos_load_to_string(str1, load1); | sos_load_to_string(str1, load1); |
sos_load_to_string(str5, load5); | sos_load_to_string(str5, load5); |
sos_load_to_string(str15, load15); | sos_load_to_string(str15, load15); |
sos_x86_videomem_printf(19, 34, | sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+3, LOAD_DISPLAY_STARTROW, |
"Kernel CPU %% (+ Idle): %s %s %s ", | "Kernel CPU %% (+ Idle): %s %s %s ", |
str1, str5, str15); | str1, str5, str15); |
|
|
return -SOS_ENOENT; | return -SOS_ENOENT; |
} | } |
| |
| |
| |
/* Map the 'init' program in user space */ | /* Map the 'init' program in user space */ |
start_uaddr = sos_binfmt_elf32_map(as_init, "init"); | start_uaddr = sos_binfmt_elf32_map(as_init, "init"); |
if (0 == start_uaddr) | if (0 == start_uaddr) |
|
|
unsigned long int upper_mem = 0; | unsigned long int upper_mem = 0; |
| |
/* Setup bochs and console, and clear the console */ | /* Setup bochs and console, and clear the console */ |
sos_bochs_setup(); | sos_bochs_subsystem_setup(); |
sos_x86_videomem_setup(); | sos_x86_videomem_setup(); |
sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE); | sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE); |
|
|
sos_x86_videomem_printf(1, 0, | sos_x86_videomem_printf(1, 0, |
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, | SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, |
"Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)", | "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)", |
"SOS article 8", ',', | "SOS article 9", ',', |
(unsigned)upper_mem); | (unsigned)upper_mem); |
} | } |
|
|
sos_x86_videomem_printf(1, 0, | sos_x86_videomem_printf(1, 0, |
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, | SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, |
"Welcome to %s%c RAM is %dMB (upper mem = 0x%x kB)", | "Welcome to %s%c RAM is %dMB (upper mem = 0x%x kB)", |
"SOS article 8", ',', | "SOS article 9", ',', |
(unsigned)upper_mem); | (unsigned)upper_mem); |
} | } |
|
|
/* Not loaded with grub, not from an enhanced bootsect */ | /* Not loaded with grub, not from an enhanced bootsect */ |
sos_x86_videomem_printf(1, 0, | sos_x86_videomem_printf(1, 0, |
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, | SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, |
"Welcome to SOS article 8"); | "Welcome to SOS article 9"); |
sos_bochs_putstring("Message in a bochs: This is SOS article 8.\n"); | sos_bochs_putstring("Message in a bochs: This is SOS article 9.\n"); |
/* Setup CPU segmentation and IRQ subsystem */ | /* Setup CPU segmentation and IRQ subsystem */ |
sos_gdt_subsystem_setup(); | sos_gdt_subsystem_setup(); |
|
|
*/ | */ |
sos_umem_vmm_subsystem_setup(); | sos_umem_vmm_subsystem_setup(); |
sos_dev_zero_subsystem_setup(); | sos_dev_zero_subsystem_setup(); |
| sos_dev_mem_chardev_setup(); |
| |
/* | /* |
* Initialize process stuff | * Initialize process stuff |
|
|
& rootfs)); | & rootfs)); |
| |
| |
| tty_subsystem_setup(); |
| sos_ttyS0_subsystem_setup(); |
| sos_console_subsystem_setup(); |
| |
| |
| |
| |
/* Start the 'init' process, which in turns launches the other | /* Start the 'init' process, which in turns launches the other |
programs */ | programs */ |
start_init(rootfs); | start_init(rootfs); |
| |
/tmp/sos-code-article8/sos/syscall.c (2005-07-01 16:39:49.000000000 +0200
) |
|
../sos-code-article9/sos/syscall.c (2005-12-28 11:44:57.000000000 +0100
) |
|
|
|
#include <sos/uaccess.h> | #include <sos/uaccess.h> |
#include "syscall.h" | #include "syscall.h" |
| |
| |
* THE syscall entry point | * THE syscall entry point |
*/ | */ |
|
|
} | } |
break; | break; |
| |
case SOS_SYSCALL_ID_FAKEMMAP: | |
{ | |
sos_uaddr_t ptr_hint_uaddr; | |
sos_uaddr_t hint_uaddr; | |
sos_size_t length; | |
sos_ui32_t prot; | |
sos_ui32_t flags; | |
sos_uaddr_t name_user; | |
sos_ui32_t offs64_hi; | |
sos_ui32_t offs64_lo; | |
sos_luoffset_t offset_in_resource; | |
char name[256]; | |
struct sos_umem_vmm_as * my_as; | |
| |
retval = sos_syscall_get7args(user_ctxt, | |
(unsigned int*)& ptr_hint_uaddr, | |
(unsigned int*)& length, | |
(unsigned int*)& prot, | |
(unsigned int*)& flags, | |
(unsigned int*)& name_user, | |
(unsigned int*)& offs64_hi, | |
(unsigned int*)& offs64_lo); | |
if (SOS_OK != retval) | |
break; | |
| |
/* Compute 64 bits offset value */ | |
offset_in_resource = offs64_hi; | |
offset_in_resource <<= 32; | |
offset_in_resource |= offs64_lo; | |
| |
retval = sos_memcpy_from_user((sos_vaddr_t)& hint_uaddr, | |
ptr_hint_uaddr, | |
sizeof(hint_uaddr)); | |
if (sizeof(hint_uaddr) != retval) | |
{ | |
retval = -SOS_EFAULT; | |
break; | |
} | |
| |
retval = sos_strzcpy_from_user(name, name_user, sizeof(name)); | |
if (SOS_OK != retval) | |
break; | |
| |
my_as | |
= sos_process_get_address_space(sos_thread_get_current()->process); | |
if ( (0 == strncmp(name, "/dev/zero", sizeof(name))) | |
|| (0 == strncmp(name, "/dev/null", sizeof(name))) ) | |
retval = sos_dev_zero_map(my_as, & hint_uaddr, length, prot, flags); | |
else if (0 == strncmp(name, "/dev/mem", sizeof(name))) | |
retval = sos_dev_physmem_map(my_as, & hint_uaddr, length, | |
offset_in_resource, prot, flags); | |
else if (0 == strncmp(name, "/dev/kmem", sizeof(name))) | |
retval = sos_dev_kmem_map(my_as, & hint_uaddr, length, | |
offset_in_resource, prot, flags); | |
else | |
retval = -SOS_ENOENT; | |
| |
if (SOS_OK == retval) | |
{ | |
if (sizeof(hint_uaddr) | |
!= sos_memcpy_to_user(ptr_hint_uaddr, | |
(sos_vaddr_t)& hint_uaddr, | |
sizeof(hint_uaddr))) | |
{ | |
sos_umem_vmm_unmap(my_as, hint_uaddr, length); | |
retval = -SOS_EFAULT; | |
} | |
} | |
| |
} | |
break; | |
| |
{ | { |
sos_uaddr_t start_uaddr; | sos_uaddr_t start_uaddr; |
|
|
{ | { |
sos_uaddr_t user_src; | sos_uaddr_t user_src; |
sos_size_t srclen; | sos_size_t srclen; |
const char * kernel_src = NULL; | char * kernel_src = NULL; |
sos_size_t dstlen; | sos_size_t dstlen; |
const char * kernel_dst; | char * kernel_dst; |
sos_uaddr_t user_fstype; | sos_uaddr_t user_fstype; |
char * kernel_fstype; | char * kernel_fstype; |
|
|
| |
if (user_src != (sos_uaddr_t)NULL) | if (user_src != (sos_uaddr_t)NULL) |
{ | { |
retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_src, user_src, srclen, 0); | retval = sos_strndup_from_user(&kernel_src, user_src, srclen, 0); |
break; | break; |
} | } |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_dst, user_dst, dstlen, 0); | retval = sos_strndup_from_user(&kernel_dst, user_dst, dstlen, 0); |
{ | { |
if (kernel_src) | if (kernel_src) |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
} | } |
break; | break; |
| |
| case SOS_SYSCALL_ID_IOCTL: |
| { |
| struct sos_fs_opened_file * of; |
| struct sos_process * proc; |
| sos_ui32_t cmd, arg; |
| int fd; |
| |
| proc = sos_thread_get_current()->process; |
| retval = sos_syscall_get3args(user_ctxt, |
| (unsigned int*)& fd, |
| (unsigned int*)& cmd, |
| (unsigned int*)& arg); |
| if (SOS_OK != retval) |
| break; |
| |
| of = sos_process_get_opened_file(proc, fd); |
| if (NULL == of) |
| { |
| retval = -SOS_EBADF; |
| break; |
| } |
| |
| /* Do the actual ioctl */ |
| retval = sos_fs_ioctl(of, cmd, arg); |
| } |
| break; |
| |
case SOS_SYSCALL_ID_CREAT: | case SOS_SYSCALL_ID_CREAT: |
{ | { |
sos_uaddr_t user_str; | sos_uaddr_t user_str; |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_oldpath, | retval = sos_strndup_from_user(&kernel_oldpath, |
user_oldpath, | user_oldpath, |
oldpathlen, 0); | oldpathlen, 0); |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_newpath, | retval = sos_strndup_from_user(&kernel_newpath, |
user_newpath, | user_newpath, |
newpathlen, 0); | newpathlen, 0); |
{ | { |
sos_kfree((sos_vaddr_t) kernel_oldpath); | sos_kfree((sos_vaddr_t) kernel_oldpath); |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_path, | retval = sos_strndup_from_user(&kernel_path, |
user_path, | user_path, |
pathlen, 0); | pathlen, 0); |
break; | break; |
| |
|
|
} | } |
break; | break; |
| |
| case SOS_SYSCALL_ID_MKNOD: |
| { |
| sos_uaddr_t user_str; |
| sos_size_t len; |
| sos_ui32_t access_rights; |
| int type; |
| char * path; |
| struct sos_fs_dev_id_t dev_id; |
| struct sos_process * proc; |
| |
| proc = sos_thread_get_current()->process; |
| retval = sos_syscall_get6args(user_ctxt, |
| (unsigned int*)& user_str, |
| (unsigned int*)& len, |
| (unsigned int*)& type, |
| (unsigned int*)& access_rights, |
| (unsigned int*)& dev_id.device_class, |
| (unsigned int*)& dev_id.device_instance); |
| if (SOS_OK != retval) |
| break; |
| |
| retval = sos_strndup_from_user(&path, user_str, len, 0); |
| if (SOS_OK != retval) |
| break; |
| |
| switch (type) |
| { |
| case SOS_FS_NODE_REGULAR_FILE: |
| retval = sos_fs_creat(proc, path, len, access_rights); |
| break; |
| |
| case SOS_FS_NODE_DIRECTORY: |
| retval = sos_fs_mkdir(proc, path, len, access_rights); |
| break; |
| |
| case SOS_FS_NODE_SYMLINK: |
| retval = -SOS_ENOSUP; |
| break; |
| |
| case SOS_FS_NODE_DEVICE_CHAR: |
| retval = sos_fs_mknod(proc, |
| path, len, type, access_rights, &dev_id); |
| break; |
| |
| default: |
| retval = -SOS_EINVAL; |
| break; |
| } |
| |
| sos_kfree((sos_vaddr_t)path); |
| } |
| break; |
| |
case SOS_SYSCALL_ID_MKDIR: | case SOS_SYSCALL_ID_MKDIR: |
{ | { |
sos_uaddr_t user_str; | sos_uaddr_t user_str; |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0); | retval = sos_strndup_from_user(&path, user_str, len, 0); |
break; | break; |
| |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
str = (char*)sos_kmalloc(len, 0); | str = (unsigned char*)sos_kmalloc(len, 0); |
{ | { |
int i; | int i; |
| |
/tmp/sos-code-article8/userland/devtest.c (1970-01-01 01:00:00.000000000 +0100
) |
|
../sos-code-article9/userland/devtest.c (2005-12-28 11:44:58.000000000 +0100
) |
|
|
|
| /* Copyright (C) 2005 David Decotigny |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. |
| */ |
| |
| #include <crt.h> |
| #include <libc.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <debug.h> |
| |
| #include "fstest_utils.h" |
| |
| /** |
| * @file devtest.c |
| * |
| * Block/character devices tests |
| */ |
| |
| int main() |
| { |
| int fd, len; |
| unsigned int sum, mem_size; |
| char buff[256]; |
| char *uaddr; |
| |
| bochs_printf("Hi from devtest\n"); |
| |
| /* Make things more complicated */ |
| fork(); |
| fork(); |
| |
| /* |
| * /dev/zero |
| */ |
| |
| TEST_EXPECT_CONDITION(fd = open("/dev/zero", O_RDWR), RETVAL == 3); |
| |
| /* Make things more complicated: spawn and stay in child */ |
| if (fork() > 0) |
| return 0; |
| |
| strzcpy(buff, "Garbage", sizeof(buff)); |
| TEST_EXPECT_CONDITION(len = read(fd, buff, sizeof(buff)), |
| RETVAL == sizeof(buff)); |
| |
| /* Make sure it is full with 0 */ |
| for (len = 0 ; len < sizeof(buff) ; len ++) |
| if (buff[len]) |
| break; |
| TEST_EXPECT_CONDITION(len, RETVAL == sizeof(buff)); |
| |
| TEST_EXPECT_CONDITION(len = write(fd, 0, 123456789), RETVAL == 123456789); |
| TEST_EXPECT_CONDITION(len = lseek(fd, 1234, SEEK_SET), RETVAL == 1234); |
| |
| /* Map it once */ |
| TEST_EXPECT_CONDITION(uaddr = mmap(NULL, 8192, |
| PROT_READ | PROT_WRITE, 0, |
| fd, 4096), RETVAL != (int)NULL); |
| |
| /* Make sure it is full with 0 */ |
| for (len = 0 ; len < 8192 ; len ++) |
| if (uaddr[len]) |
| break; |
| TEST_EXPECT_CONDITION(len, RETVAL == 8192); |
| |
| strzcpy(uaddr, "Hello /dev/zero", 8192); |
| TEST_EXPECT_CONDITION(strcmp(uaddr, "Hello /dev/zero"), RETVAL == 0); |
| |
| /* Map it again */ |
| TEST_EXPECT_CONDITION(uaddr = mmap(NULL, 8192, |
| PROT_READ | PROT_WRITE, 0, |
| fd, 4096), RETVAL != (int)NULL); |
| /* Make sure it is full with 0 */ |
| for (len = 0 ; len < 8192 ; len ++) |
| if (uaddr[len]) |
| break; |
| TEST_EXPECT_CONDITION(len, RETVAL == 8192); |
| |
| strzcpy(uaddr, "Hello /dev/zero", 8192); |
| TEST_EXPECT_CONDITION(strcmp(uaddr, "Hello /dev/zero"), RETVAL == 0); |
| |
| TEST_EXPECT_CONDITION(close(fd), RETVAL == 0); |
| |
| |
| /* |
| * /dev/null |
| */ |
| |
| TEST_EXPECT_CONDITION(fd = open("/dev/null", O_RDWR), RETVAL == 3); |
| |
| /* Make things more complicated: spawn and stay in child */ |
| if (fork() > 0) |
| return 0; |
| |
| strzcpy(buff, "Garbage", sizeof(buff)); |
| TEST_EXPECT_CONDITION(len = read(fd, buff, sizeof(buff)), |
| RETVAL == 0); |
| |
| /* Make sure buffer did not change */ |
| TEST_EXPECT_CONDITION(strcmp("Garbage", buff), RETVAL == 0); |
| |
| TEST_EXPECT_CONDITION(len = write(fd, 0, 123456789), RETVAL == 123456789); |
| TEST_EXPECT_CONDITION(len = lseek(fd, 1234, SEEK_SET), RETVAL == 1234); |
| |
| /* Map it once */ |
| TEST_EXPECT_CONDITION(uaddr = mmap(NULL, 8192, |
| PROT_READ | PROT_WRITE, 0, |
| fd, 4096), RETVAL != (int)NULL); |
| /* Make sure it is full with 0 */ |
| for (len = 0 ; len < 8192 ; len ++) |
| if (uaddr[len]) |
| break; |
| TEST_EXPECT_CONDITION(len, RETVAL == 8192); |
| |
| strzcpy(uaddr, "Hello /dev/null", 8192); |
| TEST_EXPECT_CONDITION(strcmp(uaddr, "Hello /dev/null"), RETVAL == 0); |
| |
| /* Map it again */ |
| TEST_EXPECT_CONDITION(uaddr = mmap(NULL, 8192, |
| PROT_READ | PROT_WRITE, 0, |
| fd, 4096), RETVAL != (int)NULL); |
| /* Make sure it is full with 0 */ |
| for (len = 0 ; len < 8192 ; len ++) |
| if (uaddr[len]) |
| break; |
| TEST_EXPECT_CONDITION(len, RETVAL == 8192); |
| |
| strzcpy(uaddr, "Hello /dev/null", 8192); |
| TEST_EXPECT_CONDITION(strcmp(uaddr, "Hello /dev/null"), RETVAL == 0); |
| |
| TEST_EXPECT_CONDITION(close(fd), RETVAL == 0); |
| |
| /* |
| * Invalid device instance of zero.c |
| */ |
| TEST_EXPECT_CONDITION(mknod("/dev/invalid_zero", S_IRUSR | S_IWUSR, |
| S_IFCHR, 1, 42), RETVAL == 0); |
| ls("/", 1, 1); |
| TEST_EXPECT_CONDITION(fd = open("/dev/invalid_zero", O_RDWR), RETVAL < 0); |
| TEST_EXPECT_CONDITION(unlink("/dev/invalid_zero"), RETVAL == 0); |
| |
| |
| /* |
| * Invalid device class / device instance |
| */ |
| TEST_EXPECT_CONDITION(mknod("/dev/invalid_devclass", S_IRUSR | S_IWUSR, |
| S_IFCHR, 54654, 476576), RETVAL == 0); |
| ls("/", 1, 1); |
| TEST_EXPECT_CONDITION(fd = open("/dev/invalid_devclass", |
| O_RDWR), RETVAL < 0); |
| TEST_EXPECT_CONDITION(unlink("/dev/invalid_devclass"), RETVAL == 0); |
| |
| |
| /* |
| * Test Block devices |
| */ |
| TEST_EXPECT_CONDITION(fd = open("/dev/hda", O_RDONLY), RETVAL < 0); |
| ls("/", 1, 1); |
| TEST_EXPECT_CONDITION(close(fd), RETVAL < 0); |
| |
| /* |
| * Make a checksum of all physical memory (/dev/mem) |
| */ |
| TEST_EXPECT_CONDITION(fd = open("/dev/mem", O_RDONLY), RETVAL == 3); |
| |
| /* Make things more complicated: spawn and stay in child */ |
| if (fork() > 0) |
| return 0; |
| |
| for (mem_size = 0, sum = 0 ; |
| len = read(fd, buff, sizeof(buff)), len > 0 ; |
| mem_size += len) |
| { |
| char *c; |
| if (((mem_size / sizeof(buff)) % 4000) == 0) |
| printf("Read %d MB of physical memory\n", mem_size >> 20); |
| |
| for (c = buff ; c - buff < len ; c++) |
| sum += *c; |
| } |
| TEST_EXPECT_CONDITION(mem_size, RETVAL > 0); |
| printf("Checkum of RAM (%d MB) is %x\n", mem_size >> 20, sum); |
| TEST_EXPECT_CONDITION(len = lseek(fd, 0, SEEK_SET), len == 0); |
| TEST_EXPECT_CONDITION(len = lseek(fd, 0, SEEK_END), len == mem_size); |
| TEST_EXPECT_CONDITION(close(fd), RETVAL == 0); |
| |
| /* |
| * Make a checksum of main kernel memory (/dev/kmem) |
| */ |
| TEST_EXPECT_CONDITION(fd = open("/dev/kmem", O_RDONLY), RETVAL == 3); |
| |
| /* Make things more complicated: spawn and stay in child */ |
| if (fork() > 0) |
| return 0; |
| |
| /* Seek to beginning of main .text section */ |
| TEST_EXPECT_CONDITION(lseek(fd, 0x201000, SEEK_SET), RETVAL == 0x201000); |
| for (mem_size = 0, sum = 0 ; |
| len = read(fd, buff, sizeof(buff)), len > 0 ; |
| mem_size += len) |
| { |
| char *c; |
| if (((mem_size / sizeof(buff)) % 400) == 0) |
| printf("Read %d kB of kernel memory\n", mem_size >> 10); |
| |
| for (c = buff ; c - buff < len ; c++) |
| sum += *c; |
| } |
| TEST_EXPECT_CONDITION(mem_size, RETVAL > 0); |
| printf("Checkum of main kernel area (%d kB) is %x\n", |
| mem_size >> 10, sum); |
| TEST_EXPECT_CONDITION(len = lseek(fd, 0, SEEK_SET), len == 0); |
| TEST_EXPECT_CONDITION(len = lseek(fd, 0, SEEK_END), len == 0x40000000); |
| TEST_EXPECT_CONDITION(close(fd), RETVAL == 0); |
| |
| printf("Bye from devtest\n"); |
| ls("/", 1, 1); |
| |
| /* Crash the whole kernel */ |
| bochs_printf("[31;1mNOW Crashing the whole thing !...[m\n"); |
| |
| { |
| int i; |
| for (i = 5 ; i >= 0 ; i --) |
| { |
| printf("Crashing the whole thing in %ds !... \r", i); |
| sleep(1); |
| } |
| } |
| printf("\nGO !\n"); |
| TEST_EXPECT_CONDITION(fd = open("/dev/mem", O_WRONLY), RETVAL == 3); |
| memset(buff, 0xcc, sizeof(buff)); |
| while (write(fd, buff, sizeof(buff))) |
| continue; |
| |
| return 0; |
| } |
| |
/tmp/sos-code-article8/userland/fstest.c (2005-07-01 16:39:50.000000000 +0200
) |
|
../sos-code-article9/userland/fstest.c (2005-12-28 11:44:58.000000000 +0100
) |
|
|
|
| |
#include "fstest_utils.h" | #include "fstest_utils.h" |
| |
| #define OPEN_BASE_FD 3 |
| |
/** | /** |
* @file fstest.c | * @file fstest.c |
* | * |
|
|
char buff[256]; | char buff[256]; |
| |
bochs_printf("Hi from fstest\n"); | bochs_printf("Hi from fstest\n"); |
| |
ls(".", 1, 1); | ls(".", 1, 1); |
ls("", 1, 1); | ls("", 1, 1); |
|
|
RETVAL < 0); | RETVAL < 0); |
| |
TEST_EXPECT_CONDITION(fd = open("/", O_RDWR), | TEST_EXPECT_CONDITION(fd = open("/", O_RDWR), |
RETVAL == 0); | RETVAL == OPEN_BASE_FD + 0); |
TEST_EXPECT_CONDITION(fd = open("/", O_RDONLY), | TEST_EXPECT_CONDITION(fd = open("/", O_RDONLY), |
RETVAL == 1); | RETVAL == OPEN_BASE_FD + 1); |
TEST_EXPECT_CONDITION(fd = open("/", O_WRONLY), | TEST_EXPECT_CONDITION(fd = open("/", O_WRONLY), |
RETVAL == 2); | RETVAL == OPEN_BASE_FD + 2); |
TEST_EXPECT_CONDITION(close(1), | TEST_EXPECT_CONDITION(close(OPEN_BASE_FD + 1), |
| |
TEST_EXPECT_CONDITION(fd = open("/", O_WRONLY), | TEST_EXPECT_CONDITION(fd = open("/", O_WRONLY), |
RETVAL == 1); | RETVAL == OPEN_BASE_FD + 1); |
TEST_EXPECT_CONDITION(fd = open("//", O_WRONLY), | TEST_EXPECT_CONDITION(fd = open("//", O_WRONLY), |
RETVAL == 3); | RETVAL == OPEN_BASE_FD + 3); |
TEST_EXPECT_CONDITION(fd = open("////////", O_WRONLY), | TEST_EXPECT_CONDITION(fd = open("////////", O_WRONLY), |
RETVAL == 4); | RETVAL == OPEN_BASE_FD + 4); |
TEST_EXPECT_CONDITION(fd = open("/does not exist", O_WRONLY), | TEST_EXPECT_CONDITION(fd = open("/does not exist", O_WRONLY), |
RETVAL < 0); | RETVAL < 0); |
|
|
RETVAL < 0); | RETVAL < 0); |
| |
TEST_EXPECT_CONDITION(fd = open("/", O_RDWR), | TEST_EXPECT_CONDITION(fd = open("/", O_RDWR), |
RETVAL == 5); | RETVAL == OPEN_BASE_FD + 5); |
TEST_EXPECT_CONDITION(fd = open("/tutu.txt", O_RDWR), | TEST_EXPECT_CONDITION(fd = open("/tutu.txt", O_RDWR), |
RETVAL < 0); | RETVAL < 0); |
|
|
| |
TEST_EXPECT_CONDITION(fd = open("/tutu.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("/tutu.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 6); | RETVAL == OPEN_BASE_FD + 6); |
ls("/", 1, 1); | ls("/", 1, 1); |
| |
TEST_EXPECT_CONDITION(fd = open("tutu.txt", O_RDWR | O_CREAT), | TEST_EXPECT_CONDITION(fd = open("tutu.txt", O_RDWR | O_CREAT), |
RETVAL == 7); | RETVAL == OPEN_BASE_FD + 7); |
/* O_EXCL with an already-existing file */ | /* O_EXCL with an already-existing file */ |
TEST_EXPECT_CONDITION(fd = open("tutu.txt", O_RDWR | O_CREAT | O_EXCL), | TEST_EXPECT_CONDITION(fd = open("tutu.txt", O_RDWR | O_CREAT | O_EXCL), |
|
|
| |
TEST_EXPECT_CONDITION(fd = open("/toto.txt", O_RDWR | O_CREAT | O_EXCL, | TEST_EXPECT_CONDITION(fd = open("/toto.txt", O_RDWR | O_CREAT | O_EXCL, |
S_IRWXALL), | S_IRWXALL), |
RETVAL == 8); | RETVAL == OPEN_BASE_FD + 8); |
/* O_EXCL with an already-existing file */ | /* O_EXCL with an already-existing file */ |
TEST_EXPECT_CONDITION(fd = open("toto.txt", O_RDWR | O_CREAT | O_EXCL), | TEST_EXPECT_CONDITION(fd = open("toto.txt", O_RDWR | O_CREAT | O_EXCL), |
|
|
| |
TEST_EXPECT_CONDITION(fd = open("toto.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("toto.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 9); | RETVAL == OPEN_BASE_FD + 9); |
/* Trailing slash on non-dir entries */ | /* Trailing slash on non-dir entries */ |
TEST_EXPECT_CONDITION(fd = open("toto.txt/", O_RDWR), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("toto.txt/", O_RDWR), RETVAL < 0); |
|
|
TEST_EXPECT_CONDITION(fd = open("toto1.txt", O_RDWR), | TEST_EXPECT_CONDITION(fd = open("toto1.txt", O_RDWR), |
RETVAL < 0); | RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("toto1.tx", O_RDWR | O_CREAT, S_IWUSR), | TEST_EXPECT_CONDITION(fd = open("toto1.tx", O_RDWR | O_CREAT, S_IWUSR), |
RETVAL == 10); | RETVAL == OPEN_BASE_FD + 10); |
/* Substring match */ | /* Substring match */ |
TEST_EXPECT_CONDITION(fd = open("toto.tx", O_RDWR), | TEST_EXPECT_CONDITION(fd = open("toto.tx", O_RDWR), |
RETVAL < 0); | RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("toto.tx", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("toto.tx", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 11); | RETVAL == OPEN_BASE_FD + 11); |
/* | /* |
* read/write/seek | * read/write/seek |
|
|
/* Open r/w, create read-only */ | /* Open r/w, create read-only */ |
| |
TEST_EXPECT_CONDITION(fd = open("toto2.txt", O_RDWR | O_CREAT, S_IRUSR), | TEST_EXPECT_CONDITION(fd = open("toto2.txt", O_RDWR | O_CREAT, S_IRUSR), |
RETVAL == 12); | RETVAL == OPEN_BASE_FD + 12); |
strzcpy(buff, "Garbage garbage garbage", 256); | strzcpy(buff, "Garbage garbage garbage", 256); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), |
|
|
| |
TEST_EXPECT_CONDITION(fd = open("toto3.txt", O_RDONLY | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("toto3.txt", O_RDONLY | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 13); | RETVAL == OPEN_BASE_FD + 13); |
strzcpy(buff, "Garbage garbage garbage", 256); | strzcpy(buff, "Garbage garbage garbage", 256); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0); |
|
|
{ | { |
bochs_printf("Hello from child\n"); | bochs_printf("Hello from child\n"); |
TEST_EXPECT_CONDITION(fd = open("shrd.txt", O_RDWR | O_CREAT, S_IRWXALL), | TEST_EXPECT_CONDITION(fd = open("shrd.txt", O_RDWR | O_CREAT, S_IRWXALL), |
RETVAL == 14); | RETVAL == OPEN_BASE_FD + 14); |
TEST_EXPECT_CONDITION(len = write(fd, buff, 19), | TEST_EXPECT_CONDITION(len = write(fd, buff, 19), |
RETVAL == 19); | RETVAL == 19); |
|
|
nanosleep(1, 0); | nanosleep(1, 0); |
ls("/", 1, 1); | ls("/", 1, 1); |
TEST_EXPECT_CONDITION(fd = open("shrd.txt", O_RDONLY), | TEST_EXPECT_CONDITION(fd = open("shrd.txt", O_RDONLY), |
RETVAL == 14); | RETVAL == OPEN_BASE_FD + 14); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), |
RETVAL == 19); | RETVAL == 19); |
|
|
| |
TEST_EXPECT_CONDITION(fcntl(fd, 2, 3), RETVAL < 0); /* Not supported | TEST_EXPECT_CONDITION(fcntl(fd, 2, 3), RETVAL < 0); /* Not supported |
by virtfs */ | by virtfs */ |
| TEST_EXPECT_CONDITION(ioctl(fd, 2, 3), RETVAL < 0); /* Not supported |
| by virtfs */ |
| |
ls("/", 1, 1); | ls("/", 1, 1); |
| |
|
|
TEST_EXPECT_CONDITION(chmod("toto5.txt", S_IRUSR | S_IWUSR), RETVAL == 0); | TEST_EXPECT_CONDITION(chmod("toto5.txt", S_IRUSR | S_IWUSR), RETVAL == 0); |
ls("/", 1, 1); | ls("/", 1, 1); |
| |
TEST_EXPECT_CONDITION(fd = open("toto5.txt", O_RDWR), RETVAL == 14); | TEST_EXPECT_CONDITION(fd = open("toto5.txt", O_RDWR), |
| RETVAL == OPEN_BASE_FD + 14); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0); |
| |
|
|
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); |
bochs_printf("read s='%s'\n", buff); | bochs_printf("read s='%s'\n", buff); |
| |
TEST_EXPECT_CONDITION(fd = open("toto4.txt", O_RDWR), RETVAL == 15); | TEST_EXPECT_CONDITION(fd = open("toto4.txt", O_RDWR), |
| RETVAL == OPEN_BASE_FD + 15); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); |
bochs_printf("read s='%s'\n", buff); | bochs_printf("read s='%s'\n", buff); |
|
|
| |
ls("/", 1, 1); | ls("/", 1, 1); |
| |
TEST_EXPECT_CONDITION(fd = open("toto5.txt", O_RDWR), RETVAL == 16); | TEST_EXPECT_CONDITION(fd = open("toto5.txt", O_RDWR), |
| RETVAL == OPEN_BASE_FD + 16); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0); |
| |
|
|
bochs_printf("read s='%s'\n", buff); | bochs_printf("read s='%s'\n", buff); |
TEST_EXPECT_CONDITION(strcmp(buff, "Hello world from toto5"), RETVAL == 0); | TEST_EXPECT_CONDITION(strcmp(buff, "Hello world from toto5"), RETVAL == 0); |
| |
TEST_EXPECT_CONDITION(fd = open("toto4.txt", O_RDWR), RETVAL == 17); | TEST_EXPECT_CONDITION(fd = open("toto4.txt", O_RDWR), |
| RETVAL == OPEN_BASE_FD + 17); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); |
bochs_printf("read s='%s'\n", buff); | bochs_printf("read s='%s'\n", buff); |
|
|
TEST_EXPECT_CONDITION(symlink("dangling", "toto6.txt"), RETVAL < 0); /*EEXIST*/ | TEST_EXPECT_CONDITION(symlink("dangling", "toto6.txt"), RETVAL < 0); /*EEXIST*/ |
| |
TEST_EXPECT_CONDITION(fd = open("toto6.txt", O_RDWR), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("toto6.txt", O_RDWR), RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("toto6.txt", O_RDWR | O_NOFOLLOW), RETVAL == 18); | TEST_EXPECT_CONDITION(fd = open("toto6.txt", O_RDWR | O_NOFOLLOW), |
| RETVAL == OPEN_BASE_FD + 18); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 8); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 8); |
bochs_printf("read s='%s'\n", buff); | bochs_printf("read s='%s'\n", buff); |
|
|
| |
TEST_EXPECT_CONDITION(mkdir("yoplait1", S_IRWXALL), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("yoplait1", S_IRWXALL), RETVAL == 0); |
TEST_EXPECT_CONDITION(rename("yoplait1", "mouf1"), RETVAL == 0); | TEST_EXPECT_CONDITION(rename("yoplait1", "mouf1"), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("mouf1/a", O_RDWR | O_CREAT, S_IRWXALL), RETVAL == 19); | TEST_EXPECT_CONDITION(fd = open("mouf1/a", O_RDWR | O_CREAT, S_IRWXALL), |
| RETVAL == OPEN_BASE_FD + 19); |
TEST_EXPECT_CONDITION(rmdir("mouf1"), RETVAL == 0); | TEST_EXPECT_CONDITION(rmdir("mouf1"), RETVAL == 0); |
| |
TEST_EXPECT_CONDITION(mkdir("yoplait2", S_IRWXALL), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("yoplait2", S_IRWXALL), RETVAL == 0); |
TEST_EXPECT_CONDITION(rename("yoplait2", "mouf2"), RETVAL == 0); | TEST_EXPECT_CONDITION(rename("yoplait2", "mouf2"), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("mouf2/a", O_RDWR | O_CREAT, S_IRWXALL), RETVAL == 20); | TEST_EXPECT_CONDITION(fd = open("mouf2/a", O_RDWR | O_CREAT, S_IRWXALL), |
| RETVAL == OPEN_BASE_FD + 20); |
| |
TEST_EXPECT_CONDITION(mkdir("yoplait3", S_IRWXALL), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("yoplait3", S_IRWXALL), RETVAL == 0); |
|
|
| |
ls("/", 1, 1); | ls("/", 1, 1); |
| |
| /* Not supported by virtfs */ |
| TEST_EXPECT_CONDITION(mknod("dev1", S_IRWXALL, S_IFCHR, 420, 268), |
| RETVAL == 0); |
| /* Make sure the device cannot be opened (no device should be |
| associated to it */ |
| TEST_EXPECT_CONDITION(open("dev1", O_RDONLY), RETVAL < 0); |
| TEST_EXPECT_CONDITION(unlink("dev1"), RETVAL == 0); |
| |
ls("/", 1, 1); | ls("/", 1, 1); |
ls("..", 1, 1); | ls("..", 1, 1); |
ls("../", 1, 1); | ls("../", 1, 1); |
|
|
| |
/* subdirs */ | /* subdirs */ |
TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY), RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY | O_CREAT, |
| S_IRUSR), RETVAL < 0); |
ls("/", 1, 1); | ls("/", 1, 1); |
ls("/yo1", 1, 1); | ls("/yo1", 1, 1); |
| |
TEST_EXPECT_CONDITION(mkdir("yo1", S_IRWXALL), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("yo1", S_IRWXALL), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY), RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL == 21); | TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY | O_CREAT, |
| S_IRUSR), RETVAL == OPEN_BASE_FD + 21); |
ls("/", 1, 1); | ls("/", 1, 1); |
ls("/yo1", 1, 1); | ls("/yo1", 1, 1); |
| |
TEST_EXPECT_CONDITION(mkdir("yo2", S_IRUSR | S_IXUSR), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("yo2", S_IRUSR | S_IXUSR), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("yo2/titi1.txt", O_RDONLY), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("yo2/titi1.txt", O_RDONLY), RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("yo2/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("yo2/titi1.txt", O_RDONLY | O_CREAT, |
| S_IRUSR), RETVAL < 0); |
ls("/", 1, 1); | ls("/", 1, 1); |
| |
TEST_EXPECT_CONDITION(mkdir("yo3", S_IWUSR | S_IXUSR), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("yo3", S_IWUSR | S_IXUSR), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("yo3/titi1.txt", O_RDONLY), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("yo3/titi1.txt", O_RDONLY), RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("yo3/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL == 22); | TEST_EXPECT_CONDITION(fd = open("yo3/titi1.txt", O_RDONLY | O_CREAT, |
| S_IRUSR), RETVAL == OPEN_BASE_FD + 22); |
ls("/", 1, 1); | ls("/", 1, 1); |
| |
TEST_EXPECT_CONDITION(mkdir("yo4", S_IWUSR), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("yo4", S_IWUSR), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("yo4/titi1.txt", O_RDONLY), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("yo4/titi1.txt", O_RDONLY), RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("yo4/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("yo4/titi1.txt", O_RDONLY | O_CREAT, |
| S_IRUSR), RETVAL < 0); |
ls("/", 1, 1); | ls("/", 1, 1); |
| |
|
|
ls("/", 1, 1); | ls("/", 1, 1); |
| |
/* Make sure we cannot umount if the FS is in use */ | /* Make sure we cannot umount if the FS is in use */ |
TEST_EXPECT_CONDITION(fd = open("mnt/subdir_mounted", O_DIRECTORY), RETVAL == 23); | TEST_EXPECT_CONDITION(fd = open("mnt/subdir_mounted", O_DIRECTORY), |
| RETVAL == OPEN_BASE_FD + 23); |
TEST_EXPECT_CONDITION(close(fd), RETVAL == 0); | TEST_EXPECT_CONDITION(close(fd), RETVAL == 0); |
| |
|
|
{ | { |
bochs_printf("Hello from child\n"); | bochs_printf("Hello from child\n"); |
TEST_EXPECT_CONDITION(chdir("mnt"), RETVAL == 0); | TEST_EXPECT_CONDITION(chdir("mnt"), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("subdir_mounted", O_DIRECTORY), RETVAL == 23); | TEST_EXPECT_CONDITION(fd = open("subdir_mounted", O_DIRECTORY), |
| RETVAL == OPEN_BASE_FD + 23); |
nanosleep(2, 0); | nanosleep(2, 0); |
bochs_printf("Bye from child\n"); | bochs_printf("Bye from child\n"); |
|
|
| |
TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 23); | RETVAL == OPEN_BASE_FD + 23); |
TEST_EXPECT_CONDITION(unlink("toto8.txt"), RETVAL == 0); | TEST_EXPECT_CONDITION(unlink("toto8.txt"), RETVAL == 0); |
ls("/", 1, 1); | ls("/", 1, 1); |
|
|
| |
TEST_EXPECT_CONDITION(mkdir("plotch", S_IRWXALL), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("plotch", S_IRWXALL), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("plotch/a", O_RDWR | O_CREAT, S_IRWXALL), | TEST_EXPECT_CONDITION(fd = open("plotch/a", O_RDWR | O_CREAT, S_IRWXALL), |
RETVAL == 24); | RETVAL == OPEN_BASE_FD + 24); |
TEST_EXPECT_CONDITION(unlink("plotch/a"), RETVAL == 0); | TEST_EXPECT_CONDITION(unlink("plotch/a"), RETVAL == 0); |
TEST_EXPECT_CONDITION(rmdir("plotch"), RETVAL == 0); | TEST_EXPECT_CONDITION(rmdir("plotch"), RETVAL == 0); |
|
|
TEST_EXPECT_CONDITION(mkdir("this is / a long path/tothe/destination ", S_IRWXALL), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("this is / a long path/tothe/destination ", S_IRWXALL), RETVAL == 0); |
TEST_EXPECT_CONDITION(mkdir("this is / a long path/tothe/destination / directory", S_IRWXALL), RETVAL == 0); | TEST_EXPECT_CONDITION(mkdir("this is / a long path/tothe/destination / directory", S_IRWXALL), RETVAL == 0); |
TEST_EXPECT_CONDITION(fd = open("this is / a long path/tothe/destination / directory/a", O_RDWR | O_CREAT, S_IRWXALL), | TEST_EXPECT_CONDITION(fd = open("this is / a long path/tothe/destination / directory/a", O_RDWR | O_CREAT, S_IRWXALL), |
RETVAL == 24); | RETVAL == OPEN_BASE_FD + 24); |
TEST_EXPECT_CONDITION(unlink("this is / a long path/tothe/destination / directory/a"), RETVAL == 0); | TEST_EXPECT_CONDITION(unlink("this is / a long path/tothe/destination / directory/a"), RETVAL == 0); |
TEST_EXPECT_CONDITION(rmdir("this is / a long path/tothe/destination / directory"), RETVAL == 0); | TEST_EXPECT_CONDITION(rmdir("this is / a long path/tothe/destination / directory"), RETVAL == 0); |
|
|
| |
TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 24); | RETVAL == OPEN_BASE_FD + 24); |
TEST_EXPECT_CONDITION(link("toto8.txt", "toto9.txt"), RETVAL == 0); | TEST_EXPECT_CONDITION(link("toto8.txt", "toto9.txt"), RETVAL == 0); |
TEST_EXPECT_CONDITION(unlink("toto8.txt"), RETVAL == 0); | TEST_EXPECT_CONDITION(unlink("toto8.txt"), RETVAL == 0); |
|
|
bochs_printf("read s='%s'\n", buff); | bochs_printf("read s='%s'\n", buff); |
| |
TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR), RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("toto9.txt", O_RDWR), RETVAL == 25); | TEST_EXPECT_CONDITION(fd = open("toto9.txt", O_RDWR), |
| RETVAL == OPEN_BASE_FD + 25); |
strzcpy(buff, "Garbage garbage garbage", 256); | strzcpy(buff, "Garbage garbage garbage", 256); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); |
|
|
| |
TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 26); | RETVAL == OPEN_BASE_FD + 26); |
TEST_EXPECT_CONDITION(rename("toto8.txt", "toto9.txt"), RETVAL == 0); | TEST_EXPECT_CONDITION(rename("toto8.txt", "toto9.txt"), RETVAL == 0); |
ls("/", 1, 1); | ls("/", 1, 1); |
|
|
TEST_EXPECT_CONDITION(close(fd), RETVAL == 0); | TEST_EXPECT_CONDITION(close(fd), RETVAL == 0); |
| |
TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR), RETVAL < 0); | TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR), RETVAL < 0); |
TEST_EXPECT_CONDITION(fd = open("toto9.txt", O_RDWR), RETVAL == 26); | TEST_EXPECT_CONDITION(fd = open("toto9.txt", O_RDWR), |
| RETVAL == OPEN_BASE_FD + 26); |
strzcpy(buff, "Garbage garbage garbage", 256); | strzcpy(buff, "Garbage garbage garbage", 256); |
TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); | TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24); |
|
|
/* Common use: shared file suppressed as soon as possible */ | /* Common use: shared file suppressed as soon as possible */ |
TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 26); | RETVAL == OPEN_BASE_FD + 26); |
{ | { |
char *shrd; | char *shrd; |
|
|
/* Common use: shared file suppressed as soon as possible */ | /* Common use: shared file suppressed as soon as possible */ |
TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 27); | RETVAL == OPEN_BASE_FD + 27); |
if (fork() == 0) | if (fork() == 0) |
{ | { |
|
|
ls("/", 1, 1); | ls("/", 1, 1); |
| |
/* Basic use */ | /* Basic use */ |
TEST_EXPECT_CONDITION(creat("mmap.txt", S_IRWXALL), RETVAL == 0); | TEST_EXPECT_CONDITION(creat("mmap.txt", S_IRUSR | S_IWUSR), RETVAL == 0); |
{ | { |
char *shrd; | char *shrd; |
TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 28); | RETVAL == OPEN_BASE_FD + 28); |
MAP_SHARED, fd, 4096), | MAP_SHARED, fd, 4096), |
shrd != NULL); | shrd != NULL); |
|
|
char *shrd; | char *shrd; |
TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT, | TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT, |
S_IRUSR | S_IWUSR), | S_IRUSR | S_IWUSR), |
RETVAL == 28); | RETVAL == OPEN_BASE_FD + 28); |
MAP_SHARED, fd, 4096), | MAP_SHARED, fd, 4096), |
shrd != NULL); | shrd != NULL); |
| |
/tmp/sos-code-article8/userland/libc.c (2005-07-01 16:39:50.000000000 +0200
) |
|
../sos-code-article9/userland/libc.c (2005-12-28 11:44:58.000000000 +0100
) |
|
|
|
*/ | */ |
| |
#include "crt.h" | #include "crt.h" |
#include "libc.h" | #include "string.h" |
| |
| #include "libc.h" |
| |
void * fakemmap(void *start, size_t length, int prot , int flags, | void exit (int status) |
const char *path, loff_t offset) | |
/* At kernel side, offset is considered positive */ | _sos_exit(status); |
if (offset < 0) | } |
return NULL; | |
if (0 != _sos_fakemmap(& start, length, prot, flags, path, offset)) | |
return NULL; | |
return start; | pid_t fork(void) |
| { |
| return _sos_fork(); |
| } |
| |
| |
| int exec(const char *progname) |
| { |
| return _sos_exec(progname); |
| } |
| |
| |
| int sleep(unsigned int seconds) |
| { |
| return nanosleep(seconds, 0); |
| } |
| |
| |
| int nanosleep(unsigned long int sec, |
| unsigned long int nanosec) |
| { |
| return _sos_nanosleep(sec, nanosec); |
| } |
| |
| |
| |
| int munmap(void * start, size_t length) |
| { |
| return _sos_munmap(start, length); |
| |
| |
|
|
} | } |
| |
| |
| int mprotect(const void *addr, size_t len, int prot) |
| { |
| return _sos_mprotect(addr, len, prot); |
| } |
| |
| |
/** | /** |
* The presence of this global variable without any protected access | * The presence of this global variable without any protected access |
* to it explains why the "brk/sbrk" functions below are MT-unsafe ! | * to it explains why the "brk/sbrk" functions below are MT-unsafe ! |
|
|
} | } |
| |
| |
| |
| int mount(const char *source, const char *target, |
| const char *filesystemtype, unsigned long mountflags, |
| const char *data) |
| { |
| return _sos_mount(source, target, filesystemtype, mountflags, data); |
| } |
| |
| |
| int umount(const char *target) |
| { |
| return _sos_umount(target); |
| } |
| |
| |
| void sync(void) |
| { |
| return _sos_sync(); |
| } |
| |
| |
| int statvfs(const char *path, struct statvfs *buf) |
| { |
| return _sos_statvfs(path, buf); |
| } |
| |
| |
int open(const char *pathname, int flags, /* mode_t mode */...) | int open(const char *pathname, int flags, /* mode_t mode */...) |
{ | { |
va_list ap; | va_list ap; |
|
|
} | } |
| |
| |
| int close(int fd) |
| { |
| return _sos_close(fd); |
| } |
| |
| |
int read(int fd, char * buf, size_t len) | int read(int fd, char * buf, size_t len) |
{ | { |
int retval = _sos_read(fd, buf, & len); | int retval = _sos_read(fd, buf, & len); |
|
|
} | } |
| |
| |
| int ftruncate64(int fd, loff_t length) |
| { |
| return _sos_ftruncate64(fd, length); |
| } |
| |
| |
| int fcntl(int fd, int cmd, int arg) |
| { |
| return _sos_fcntl(fd, cmd, arg); |
| } |
| |
| |
| int ioctl(int fd, int cmd, int arg) |
| { |
| return _sos_ioctl(fd, cmd, arg); |
| } |
| |
| |
| int creat(const char *pathname, mode_t mode) |
| { |
| return _sos_creat(pathname, mode); |
| } |
| |
| int link (const char *oldpath, const char *newpath) |
| { |
| return _sos_link(oldpath, newpath); |
| } |
| |
| |
| int unlink(const char *pathname) |
| { |
| return _sos_unlink(pathname); |
| } |
| |
| |
| int rename(const char *oldpath, const char *newpath) |
| { |
| return _sos_rename(oldpath, newpath); |
| } |
| |
| |
| int symlink(const char *target, const char *path) |
| { |
| return _sos_symlink(target, path); |
| } |
| |
| |
| int mknod(const char *pathname, mode_t mode, |
| int type, |
| unsigned int major, unsigned minor) |
| { |
| if (type == S_IFREG) |
| return creat(pathname, mode); |
| |
| return _sos_mknod(pathname, mode, type, |
| major, minor); |
| } |
| |
| |
| int mkdir(const char *pathname, mode_t mode) |
| { |
| return _sos_mkdir(pathname, mode); |
| } |
| |
| |
| int rmdir(const char *pathname) |
| { |
| return _sos_rmdir(pathname); |
| } |
| |
| |
| int chmod(const char *path, mode_t mode) |
| { |
| return _sos_chmod(path, mode); |
| } |
| |
| |
struct sos_DIR_struct | struct sos_DIR_struct |
{ | { |
int fd; | int fd; |
|
|
{ | { |
return _sos_stat(file_name, FALSE, buf); | return _sos_stat(file_name, FALSE, buf); |
} | } |
| |
| |
| int chroot(const char *path) |
| { |
| return _sos_chroot(path); |
| } |
| |
| |
| int chdir(const char *path) |
| { |
| return _sos_chdir(path); |
| } |
| |
| int fchdir(int fd) |
| { |
| return _sos_fchdir(fd); |
| } |
| |
| |
| |
| int printf (const char *format, ...) |
| { |
| char buff[4096]; |
| va_list ap; |
| |
| va_start(ap, format); |
| vsnprintf(buff, sizeof(buff), format, ap); |
| va_end(ap); |
| |
| return write (1, buff, strlen(buff)); |
| } |
| |
| |
| |
/tmp/sos-code-article8/userland/libc.h (2005-07-01 16:39:50.000000000 +0200
) |
|
../sos-code-article9/userland/libc.h (2005-12-28 11:44:58.000000000 +0100
) |
|
|
|
/** | /** |
* The most important function of a C program ! ;) | * The most important function of a C program ! ;) |
*/ | */ |
void exit (int status) | void exit (int status); |
__attribute__((noreturn, alias("_sos_exit"))); | |
| |
/** | /** |
* Function to duplicate the current running process | * Function to duplicate the current running process |
*/ | */ |
pid_t fork(void) | pid_t fork(void); |
__attribute__ ((alias("_sos_fork"))); | |
| |
/** | /** |
* Function to re-initialize the address space of the current process | * Function to re-initialize the address space of the current process |
* with that of the program 'progname' | * with that of the program 'progname' |
*/ | */ |
int exec(const char *progname) | int exec(const char *progname); |
__attribute__ ((alias("_sos_exec"))); | |
| |
int nanosleep(unsigned long int sec, | int nanosleep(unsigned long int sec, |
unsigned long int nanosec) | unsigned long int nanosec); |
__attribute__ ((alias("_sos_nanosleep"))); | |
| |
| int sleep(unsigned int seconds); |
| |
/** | /** |
* These flags (for mmap API) MUST be consistent with those defined in | * These flags (for mmap API) MUST be consistent with those defined in |
|
|
#define MAP_SHARED (1 << 0) | #define MAP_SHARED (1 << 0) |
#define MAP_FIXED (1 << 31) | #define MAP_FIXED (1 << 31) |
| |
/** | |
* Non standard version of mmap. Differences with standard version: | |
* - the resource to map is given by its "path", not by a file descriptor | |
* - the offset is a signed 64bits, and MUST be >= 0 (error otherwise) | |
* - no errno support | |
*/ | |
void * fakemmap(void *start, size_t length, int prot , int flags, | |
const char *path, loff_t offset); | |
| |
/** | /** |
* Unmap the given user address interval | * Unmap the given user address interval |
*/ | */ |
int munmap(void * start, size_t length) | int munmap(void * start, size_t length); |
__attribute__ ((alias("_sos_munmap"))); | |
| |
/** | /** |
* Change the access permissions of the given user address interval | * Change the access permissions of the given user address interval |
*/ | */ |
int mprotect(const void *addr, size_t len, int prot) | int mprotect(const void *addr, size_t len, int prot); |
__attribute__ ((alias("_sos_mprotect"))); | |
| |
| |
/** | /** |
|
|
| |
int mount(const char *source, const char *target, | int mount(const char *source, const char *target, |
const char *filesystemtype, unsigned long mountflags, | const char *filesystemtype, unsigned long mountflags, |
const char *data) | const char *data); |
__attribute__ ((alias("_sos_mount"))); | |
int umount(const char *target) | |
__attribute__ ((alias("_sos_umount"))); | int umount(const char *target); |
void sync(void) | |
__attribute__ ((alias("_sos_sync"))); | |
| void sync(void); |
| |
struct statvfs | struct statvfs |
{ | { |
| unsigned int f_rdev_major; |
| unsigned int f_rdev_minor; |
size_t f_sz_total; /**< Total size */ | size_t f_sz_total; /**< Total size */ |
size_t f_sz_free; /**< Size left on device */ | size_t f_sz_free; /**< Size left on device */ |
unsigned int f_node_total;/**< Total allocatable FS nodes */ | unsigned int f_node_total;/**< Total allocatable FS nodes */ |
|
|
unsigned int f_flags; | unsigned int f_flags; |
}; | }; |
| |
int statvfs(const char *path, struct statvfs *buf) | int statvfs(const char *path, struct statvfs *buf); |
__attribute__ ((alias("_sos_statvfs"))); | |
#define O_EXCL (1 << 0) | #define O_EXCL (1 << 0) |
#define O_CREAT (1 << 1) | #define O_CREAT (1 << 1) |
#define O_NOFOLLOW (1 << 2) | #define O_TRUNC (1 << 2) |
#define O_DIRECTORY (1 << 3) /* Incompatible with CREAT */ | #define O_NOFOLLOW (1 << 3) |
#define O_SYNC (1 << 4) | #define O_DIRECTORY (1 << 4) /* Incompatible with CREAT/TRUNC */ |
| #define O_SYNC (1 << 5) |
#define O_RDONLY (1 << 16) | #define O_RDONLY (1 << 16) |
#define O_WRONLY (1 << 17) | #define O_WRONLY (1 << 17) |
|
|
| |
int open(const char *pathname, int flags, /* mode_t mode */...); | int open(const char *pathname, int flags, /* mode_t mode */...); |
| |
int close(int fd) | int close(int fd); |
__attribute__ ((alias("_sos_close"))); | |
int read(int fd, char * buf, size_t len); | int read(int fd, char * buf, size_t len); |
int write(int fd, const char * buf, size_t len); | int write(int fd, const char * buf, size_t len); |
|
|
void * mmap(void *start, size_t length, int prot , int flags, | void * mmap(void *start, size_t length, int prot , int flags, |
int fd, loff_t offset); | int fd, loff_t offset); |
int ftruncate(int fd, off_t length); | int ftruncate(int fd, off_t length); |
int ftruncate64(int fd, loff_t length) | int ftruncate64(int fd, loff_t length); |
__attribute__ ((alias("_sos_ftruncate64"))); | int fcntl(int fd, int cmd, int arg); |
int fcntl(int fd, int cmd, int arg) | int ioctl(int fd, int cmd, int arg); |
__attribute__ ((alias("_sos_fcntl"))); | |
| int creat(const char *pathname, mode_t mode); |
int creat(const char *pathname, mode_t mode) | int link (const char *oldpath, const char *newpath); |
__attribute__ ((alias("_sos_creat"))); | int unlink(const char *pathname); |
int link (const char *oldpath, const char *newpath) | int rename(const char *oldpath, const char *newpath); |
__attribute__ ((alias("_sos_link"))); | int symlink(const char *target, const char *path); |
int unlink(const char *pathname) | |
__attribute__ ((alias("_sos_unlink"))); | /* Same as sos_fs_node_type_t in kernel fs.h */ |
int rename(const char *oldpath, const char *newpath) | #define S_IFREG 0x42 |
__attribute__ ((alias("_sos_rename"))); | #define S_IFDIR 0x24 |
int symlink(const char *target, const char *path) | #define S_IFLNK 0x84 |
__attribute__ ((alias("_sos_symlink"))); | #define S_IFCHR 0x48 |
| int mknod(const char *pathname, mode_t mode, |
int mkdir(const char *pathname, mode_t mode) | int type, |
__attribute__ ((alias("_sos_mkdir"))); | unsigned int major, unsigned minor); |
int rmdir(const char *pathname) | |
__attribute__ ((alias("_sos_rmdir"))); | |
| int mkdir(const char *pathname, mode_t mode); |
| |
| |
| int rmdir(const char *pathname); |
| |
| |
| int chmod(const char *path, mode_t mode); |
int chmod(const char *path, mode_t mode) | |
__attribute__ ((alias("_sos_chmod"))); | |
struct dirent | struct dirent |
{ | { |
unsigned long long int storage_location; | unsigned long long int storage_location; |
unsigned long long int offset_in_dirfile; | unsigned long long int offset_in_dirfile; |
| |
/* Same as sos_fs_node_type_t in kernel fs.h */ | |
#define S_IFREG 0x42 | |
#define S_IFDIR 0x24 | |
#define S_IFLNK 0x84 | |
unsigned short namelen; | unsigned short namelen; |
| |
|
|
| |
struct stat | struct stat |
{ | { |
| unsigned int st_rdev_major; |
| unsigned int st_rdev_minor; |
int st_type; | int st_type; |
unsigned long long int st_storage_location; | unsigned long long int st_storage_location; |
int st_access_rights; | int st_access_rights; |
|
|
| |
int stat(const char *file_name, struct stat *buf); | int stat(const char *file_name, struct stat *buf); |
int lstat(const char *file_name, struct stat *buf); | int lstat(const char *file_name, struct stat *buf); |
| int chroot(const char *path); |
| int chdir(const char *path); |
| int fchdir(int fd); |
| |
int chroot(const char *path) | int printf(const char *, ...); |
__attribute__ ((alias("_sos_chroot"))); | |
int chdir(const char *path) | |
__attribute__ ((alias("_sos_chdir"))); | |
int fchdir(int fd) | |
__attribute__ ((alias("_sos_fchdir"))); | |
| |
| |
#endif /* _SOS_USER_LIBC_H_ */ | #endif /* _SOS_USER_LIBC_H_ */ |
| |
/tmp/sos-code-article8/userland/shell.c (1970-01-01 01:00:00.000000000 +0100
) |
|
../sos-code-article9/userland/shell.c (2005-12-28 11:44:58.000000000 +0100
) |
|
|
|
| /* Copyright (C) 2005 David Decotigny, Thomas Petazzoni |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. |
| */ |
| |
| #include <crt.h> |
| #include <libc.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <debug.h> |
| #include <drivers/devices.h> |
| |
| #include "fstest_utils.h" |
| |
| /** |
| * @file shell.c |
| * |
| * Small shell. |
| */ |
| |
| static int shell_uname (int argc, char *argv[]) |
| { |
| printf ("SOS article 9\n"); |
| return 0; |
| } |
| |
| static void shell_ls_internal(int detailed, int recursive, int reclevel) |
| { |
| char tab[256], *c; |
| int i; |
| struct dirent * dirent; |
| DIR * here; |
| |
| here = opendir("."); |
| if (! here) |
| return; |
| |
| /* Build initial tabulation */ |
| if (recursive) |
| { |
| for (c = tab, i = 0 ; (i < reclevel) && (i < sizeof(tab)/2) ; i++) |
| { |
| *c++ = ' '; |
| *c++ = ' '; |
| } |
| *c++ = '\0'; |
| } |
| else |
| *tab = '\0'; |
| |
| while ((dirent = readdir(here)) != NULL) |
| { |
| char entrychar; |
| char * entrysuffix; |
| |
| switch(dirent->type) |
| { |
| case S_IFREG: entrychar='-'; entrysuffix=""; break; |
| case S_IFDIR: entrychar='d'; entrysuffix="/"; break; |
| case S_IFLNK: entrychar='l'; entrysuffix="@"; break; |
| case S_IFCHR: entrychar='c'; entrysuffix=NULL; break; |
| default: entrychar='?'; entrysuffix="?!?"; break; |
| } |
| |
| if (detailed) |
| { |
| struct stat stat; |
| char target_name[SOS_FS_DIRENT_NAME_MAXLEN]; |
| char majorminor[24]; |
| |
| if (lstat(dirent->name, & stat)) |
| continue; |
| |
| *target_name = '\0'; |
| if (stat.st_type == S_IFLNK) |
| { |
| int fd = open(dirent->name, O_RDONLY | O_NOFOLLOW); |
| if (fd >= 0) |
| { |
| int len = read(fd, target_name, sizeof(target_name) - 1); |
| if (len < 0) |
| *target_name='\0'; |
| else |
| target_name[len] = '\0'; |
| close(fd); |
| } |
| } |
| else if (stat.st_type == S_IFCHR) |
| { |
| snprintf(majorminor, sizeof(majorminor), " %d,%d", |
| stat.st_rdev_major, stat.st_rdev_minor); |
| entrysuffix = majorminor; |
| } |
| |
| printf("%s%c%c%c%c %lld %s%s%s%s (location=0x%llx)\n", |
| tab, entrychar, |
| (stat.st_access_rights&S_IRUSR)?'r':'-', |
| (stat.st_access_rights&S_IWUSR)?'w':'-', |
| (stat.st_access_rights&S_IXUSR)?'x':'-', |
| stat.st_size, |
| dirent->name, |
| entrysuffix, |
| (stat.st_type==S_IFLNK)?" -> ":"", |
| target_name, |
| stat.st_storage_location); |
| } |
| else |
| printf("%s%s%s\n", |
| tab, dirent->name, entrysuffix); |
| |
| /* Next iteration */ |
| if (recursive) |
| { |
| int fd_here = dirfd(here); |
| if (chdir(dirent->name)) |
| continue; |
| shell_ls_internal(detailed, recursive, reclevel+1); |
| if(fchdir(fd_here)) |
| { |
| closedir(here); |
| return; |
| } |
| } |
| } |
| closedir(here); |
| } |
| |
| static void shell_ls(const char * path, int detailed, int recursive) |
| { |
| int fd_here = open(".", O_RDONLY | O_DIRECTORY); |
| if (fd_here < 0) |
| return; |
| |
| if (chdir(path)) |
| { |
| close(fd_here); |
| return; |
| } |
| |
| shell_ls_internal(detailed, recursive, 1); |
| |
| fchdir(fd_here); |
| close(fd_here); |
| } |
| |
| static int shell_touch (int argc, char *argv[]) |
| { |
| return creat (argv[1], S_IRUSR | S_IWUSR); |
| } |
| |
| static int shell_mkdir (int argc, char *argv[]) |
| { |
| return mkdir (argv[1], S_IRUSR | S_IWUSR | S_IXUSR); |
| } |
| |
| static int shell_cat (int argc, char *argv[]) |
| { |
| int fd; |
| char buf[4096]; |
| int len; |
| |
| fd = open (argv[1], O_RDONLY); |
| if (fd < 0) { |
| printf ("Cannot open '%s'\n", argv[1]); |
| return -1; |
| } |
| |
| while (1) |
| { |
| len = read (fd, buf, sizeof(buf)-1); |
| if (len <= 0) |
| break; |
| buf[len] = '\0'; |
| |
| printf ("%s", buf); |
| } |
| |
| close (fd); |
| return 0; |
| } |
| |
| static int shell_edit (int argc, char *argv[]) |
| { |
| int fd; |
| char buf[16]; |
| int len; |
| |
| fd = open (argv[1], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); |
| if (fd < 0) { |
| printf ("Cannot create '%s': %d\n", argv[1], fd); |
| return -1; |
| } |
| |
| /* Activate echo and activate again canonical mode */ |
| ioctl (0, SOS_IOCTL_TTY_SETPARAM, SOS_IOCTLPARAM_TTY_ECHO); |
| ioctl (0, SOS_IOCTL_TTY_SETPARAM, SOS_IOCTLPARAM_TTY_CANON); |
| |
| while (1) |
| { |
| len = read (0, buf, sizeof(buf)); |
| if (len <= 1) |
| break; |
| |
| bochs_printf ("Writing %d bytes\n", len); |
| len = write (fd, buf, len); |
| if (len <= 0) { |
| printf ("Cannot write to '%s': %d\n", argv[1], len); |
| break; |
| } |
| } |
| |
| /* Desactivate echo and remove canonical mode */ |
| ioctl (0, SOS_IOCTL_TTY_RESETPARAM, SOS_IOCTLPARAM_TTY_ECHO); |
| ioctl (0, SOS_IOCTL_TTY_RESETPARAM, SOS_IOCTLPARAM_TTY_CANON); |
| |
| close (fd); |
| return 0; |
| } |
| |
| static int shell_hexdump (int argc, char *argv[]) |
| { |
| int fd; |
| char buf[16]; |
| int count = 0; |
| int len; |
| |
| fd = open (argv[1], O_RDONLY); |
| if (fd < 0) { |
| printf ("Cannot open '%s': %d\n", argv[1], fd); |
| return -1; |
| } |
| |
| while (1) |
| { |
| int i; |
| |
| len = read (fd, buf, sizeof(buf)); |
| if (len <= 0) |
| break; |
| |
| if (count < 0x10) |
| printf ("00%x ", count); |
| else if (count < 0x100) |
| printf ("0%x ", count); |
| else if (count < 0x1000) |
| printf ("%x ", count); |
| |
| for (i = 0; i < len; i++) |
| { |
| if (buf[i] < 0x10) |
| printf ("0%x ", buf[i]); |
| else |
| printf ("%x ", buf[i]); |
| } |
| |
| printf ("\n"); |
| |
| count += len; |
| } |
| |
| close (fd); |
| return 0; |
| } |
| |
| static int shell_test (int argc, char *argv[]) |
| { |
| int i; |
| for (i = 0; i < argc; i++) |
| { |
| printf ("argv[%d] = %s\n", i, argv[i]); |
| } |
| return 0; |
| } |
| |
| |
| static int shell_devtest (int argc, char *argv[]) |
| { |
| bochs_printf("WARNING: This test will eventually write 0 on kernel code !\n"); |
| bochs_printf("This WILL crash the kernel (as expected...) !\n"); |
| printf("WARNING: This test will eventually write 0 on kernel code !\n"); |
| printf("This WILL crash the kernel (as expected...) !\n"); |
| if (fork() == 0) |
| exec("devtest"); |
| return 0; |
| } |
| |
| |
| static int shell_fstest (int argc, char *argv[]) |
| { |
| if (fork() == 0) |
| exec("fstest"); |
| return 0; |
| } |
| |
| void command_exec (char * cmd) |
| { |
| char *c; |
| int argc = 1, i; |
| char **argv; |
| |
| for (c = cmd; *c != '\0'; c++) |
| if (*c == ' ') |
| argc++; |
| |
| argv = malloc (argc * sizeof(char*)); |
| if (argv == NULL) |
| return; |
| |
| for (i = 0, c = cmd; i < argc; i++) |
| { |
| argv[i] = c; |
| while (*c != ' ' && *c != '\0') |
| c++; |
| *c = '\0'; |
| c++; |
| } |
| |
| if (! strcmp (argv[0], "uname")) |
| shell_uname(argc, argv); |
| |
| else if (! strcmp (argv[0], "ls")) |
| { |
| if (argv[1]) |
| shell_ls (argv[1], 1, 0); |
| else |
| shell_ls (".", 1, 0); |
| } |
| |
| else if (! strcmp (argv[0], "touch")) |
| { |
| shell_touch (argc, argv); |
| } |
| |
| else if (! strcmp (argv[0], "mkdir")) |
| { |
| shell_mkdir (argc, argv); |
| } |
| |
| else if (! strcmp (argv[0], "cat")) |
| { |
| shell_cat (argc, argv); |
| } |
| |
| else if (! strcmp (argv[0], "edit")) |
| { |
| shell_edit (argc, argv); |
| } |
| |
| else if (! strcmp (argv[0], "hexdump")) |
| { |
| shell_hexdump (argc, argv); |
| } |
| else if (! strcmp (argv[0], "test")) |
| { |
| shell_test (argc, argv); |
| } |
| else if (! strcmp (argv[0], "devtest")) |
| { |
| shell_devtest (argc, argv); |
| } |
| else if (! strcmp (argv[0], "fstest")) |
| { |
| shell_fstest (argc, argv); |
| } |
| |
| |
| else |
| printf ("Command not found\n"); |
| |
| free (argv); |
| } |
| |
| int main() |
| { |
| char buffer[256]; |
| int i; |
| char chr; |
| |
| ioctl (0, SOS_IOCTL_TTY_RESETPARAM, SOS_IOCTLPARAM_TTY_CANON); |
| |
| while (1) |
| { |
| memset (buffer, 0, sizeof(buffer)); |
| i = 0; |
| printf ("$ "); |
| |
| while (1) |
| { |
| read (0, & chr, 1); |
| if (chr == '\n') |
| { |
| buffer[i] = '\0'; |
| printf ("\n"); |
| if (i != 0) |
| command_exec (buffer); |
| break; |
| } |
| else if (chr == '\b') |
| { |
| if (i > 0) |
| { |
| i--; |
| printf ("\b"); |
| } |
| } |
| |
| else if (i < 256) |
| { |
| buffer[i++] = chr; |
| printf ("%c", chr); |
| } |
| else |
| printf ("%c", chr); |
| } |
| } |
| |
| return 0; |
| } |
| |