export의 반대는..

unset '환경변수이름'

'Embedded Lab > linux, x86' 카테고리의 다른 글

[blktrace1]  (0) 2013.04.08
[printk 로그 레벨]  (0) 2013.04.08
[간단한 블록 디바이스 드라이버 모듈(램디스크)]  (0) 2013.04.07
[환경변수 삭제]  (0) 2013.03.29
[리눅스 압축명령]  (0) 2013.03.28
Posted by cyj4369
,

My current work involves writing my first Linux block device driver. Going to the web to find a sample, I discovered Jonathan Corbet's Simple Block Driver article with its associated block driver example code. It's a nice succinct implementation of a ramdisk - pretty much the simplest working block device. There's only one problem, though, the article was written in 2003, when kernel 2.6.0 was the new kid on the block. Trying to build it on openSUSE 11.2 with kernel 2.6.31 just produced a slew of compile errors. A bit of research revealed that there were major changes to the kernel block device interface in 2.6.31, so I would have to port the example to get it working.

About a day and a half of poring through the kernel source and the excellent LDD3 (hardcopy) later, I had a running simple block driver for kernel 2.6.31. I've also tested it successfully on SUSE 11 SP1 Beta, which uses kernel 2.6.32. Here's the code, followed by instructions for getting it working.

sbd.c

/*
 * A sample, extra-simple block driver. Updated for kernel 2.6.31.
 *
 * (C) 2003 Eklektix, Inc.
 * (C) 2010 Pat Patterson <pat at superpat dot com>
 * Redistributable under the terms of the GNU GPL.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h> /* printk() */
#include <linux/fs.h>     /* everything... */
#include <linux/errno.h>  /* error codes */
#include <linux/types.h>  /* size_t */
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>

MODULE_LICENSE("Dual BSD/GPL");
static char *Version = "1.4";

static int major_num = 0;
module_param(major_num, int, 0);
static int logical_block_size = 512;
module_param(logical_block_size, int, 0);
static int nsectors = 1024; /* How big the drive is */
module_param(nsectors, int, 0);

/*
 * We can tweak our hardware sector size, but the kernel talks to us
 * in terms of small sectors, always.
 */
#define KERNEL_SECTOR_SIZE 512

/*
 * Our request queue.
 */
static struct request_queue *Queue;

/*
 * The internal representation of our device.
 */
static struct sbd_device {
	unsigned long size;
	spinlock_t lock;
	u8 *data;
	struct gendisk *gd;
} Device;

/*
 * Handle an I/O request.
 */
static void sbd_transfer(struct sbd_device *dev, sector_t sector,
		unsigned long nsect, char *buffer, int write) {
	unsigned long offset = sector * logical_block_size;
	unsigned long nbytes = nsect * logical_block_size;

	if ((offset + nbytes) > dev->size) {
		printk (KERN_NOTICE "sbd: Beyond-end write (%ld %ld)\n", offset, nbytes);
		return;
	}
	if (write)
		memcpy(dev->data + offset, buffer, nbytes);
	else
		memcpy(buffer, dev->data + offset, nbytes);
}

static void sbd_request(struct request_queue *q) {
	struct request *req;

	req = blk_fetch_request(q);
	while (req != NULL) {
		// blk_fs_request() was removed in 2.6.36 - many thanks to
		// Christian Paro for the heads up and fix...
		//if (!blk_fs_request(req)) {
		if (req == NULL || (req->cmd_type != REQ_TYPE_FS)) {
			printk (KERN_NOTICE "Skip non-CMD request\n");
			__blk_end_request_all(req, -EIO);
			continue;
		}
		sbd_transfer(&Device, blk_rq_pos(req), blk_rq_cur_sectors(req),
				req->buffer, rq_data_dir(req));
		if ( ! __blk_end_request_cur(req, 0) ) {
			req = blk_fetch_request(q);
		}
	}
}

/*
 * The HDIO_GETGEO ioctl is handled in blkdev_ioctl(), which
 * calls this. We need to implement getgeo, since we can't
 * use tools such as fdisk to partition the drive otherwise.
 */
int sbd_getgeo(struct block_device * block_device, struct hd_geometry * geo) {
	long size;

	/* We have no real geometry, of course, so make something up. */
	size = Device.size * (logical_block_size / KERNEL_SECTOR_SIZE);
	geo->cylinders = (size & ~0x3f) >> 6;
	geo->heads = 4;
	geo->sectors = 16;
	geo->start = 0;
	return 0;
}

/*
 * The device operations structure.
 */
static struct block_device_operations sbd_ops = {
		.owner  = THIS_MODULE,
		.getgeo = sbd_getgeo
};

static int __init sbd_init(void) {
	/*
	 * Set up our internal device.
	 */
	Device.size = nsectors * logical_block_size;
	spin_lock_init(&Device.lock);
	Device.data = vmalloc(Device.size);
	if (Device.data == NULL)
		return -ENOMEM;
	/*
	 * Get a request queue.
	 */
	Queue = blk_init_queue(sbd_request, &Device.lock);
	if (Queue == NULL)
		goto out;
	blk_queue_logical_block_size(Queue, logical_block_size);
	/*
	 * Get registered.
	 */
	major_num = register_blkdev(major_num, "sbd");
	if (major_num < 0) {
		printk(KERN_WARNING "sbd: unable to get major number\n");
		goto out;
	}
	/*
	 * And the gendisk structure.
	 */
	Device.gd = alloc_disk(16);
	if (!Device.gd)
		goto out_unregister;
	Device.gd->major = major_num;
	Device.gd->first_minor = 0;
	Device.gd->fops = &sbd_ops;
	Device.gd->private_data = &Device;
	strcpy(Device.gd->disk_name, "sbd0");
	set_capacity(Device.gd, nsectors);
	Device.gd->queue = Queue;
	add_disk(Device.gd);

	return 0;

out_unregister:
	unregister_blkdev(major_num, "sbd");
out:
	vfree(Device.data);
	return -ENOMEM;
}

static void __exit sbd_exit(void)
{
	del_gendisk(Device.gd);
	put_disk(Device.gd);
	unregister_blkdev(major_num, "sbd");
	blk_cleanup_queue(Queue);
	vfree(Device.data);
}

module_init(sbd_init);
module_exit(sbd_exit);

Makefile

obj-m := sbd.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

There are two main areas of change compared with Jonathan's original:

  • sbd_request() uses the blk_fetch_request()blk_rq_pos(),blk_rq_cur_sectors() and __blk_end_request_cur() functions rather thanelv_next_request()req->sectorreq->current_nr_sectors andend_request() respectively. The structure of the loop also changes so we handle each sector from the request individually. One outstanding task for me is to investigate whetherreq->buffer holds all of the data for the entire request, so I can handle it all in one shot, rather than sector-by-sector. My first attempt resulted in the (virtual) machine hanging when I installed the driver, so I clearly need to do some more work in this area!
  • The driver implements the getgeo operation (in sbd_getgeo), rather than ioctl, since blkdev_ioctl now handles HDIO_GETGEO by calling the driver's getgeo function. This is a nice simplification since it moves a copy_to_user call out of each driver and into the kernel.

Before building, ensure you have the kernel source, headers, gcc, make etc - if you've read this far, you likely have all this and/or know how to get it, so I won't spell it all out here. You'll also need to go to the kernel source directory and do the following to prepare your build environment, if you have not already done so:

cd /usr/src/`uname -r`
make oldconfig && make prepare

Now, back in the directory with the sbd source, you can build it:

make -C /lib/modules/`uname -r`/build M=`pwd` modules

You'll see a warning about 'Version' being defined, but not used, but don't worry about that :-). Now we can load the module, partition the ramdisk, make a filesystem, mount it, and create a file:

opensuse:/home/pat/sbd # insmod sbd.ko
opensuse:/home/pat/sbd # fdisk /dev/sbd0
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x5f93978c.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-16, default 1):
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-16, default 16):
Using default value 16

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
opensuse:/home/pat/sbd # mkfs /dev/sbd0p1
mke2fs 1.41.9 (22-Aug-2009)
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
64 inodes, 504 blocks
25 blocks (4.96%) reserved for the super user
First data block=1
Maximum filesystem blocks=524288
1 block group
8192 blocks per group, 8192 fragments per group
64 inodes per group

Writing inode tables: done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 24 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
opensuse:/home/pat/sbd # mount /dev/sbd0p1 /mnt
opensuse:/home/pat/sbd # echo Hi > /mnt/file1
opensuse:/home/pat/sbd # cat /mnt/file1
Hi
opensuse:/home/pat/sbd # ls -l /mnt
total 13
-rw-r--r-- 1 root root     3 2010-04-29 07:04 file1
drwx------ 2 root root 12288 2010-04-29 07:04 lost+found
opensuse:/home/pat/sbd # umount /mnt
opensuse:/home/pat/sbd # rmmod sbd

Hopefully this all works for you, and is as useful for you as it has been for me. Many thanks to Jonathan for the original version and the excellent LDD3. One final piece of housekeeping - although the comment at the top of sbd.c mentions only GPL, the MODULE_LICENSE macro specifies "Dual BSD/GPL". I am interpreting the original code as being under the dual GPL/BSD license and this version is similarly dual licensed.

UPDATE (Feb 5 2011) See the comment by Michele regarding changes to logical_block_size!


출처 : http://blog.superpat.com/2010/05/04/a-simple-block-driver-for-linux-kernel-2-6-31/

'Embedded Lab > linux, x86' 카테고리의 다른 글

[printk 로그 레벨]  (0) 2013.04.08
[환경변수 삭제]  (0) 2013.04.07
[환경변수 삭제]  (0) 2013.03.29
[리눅스 압축명령]  (0) 2013.03.28
[리눅스가 부팅이 안될 때/MBR에 GRUB을 다시 설치하는 방법]  (0) 2013.03.28
Posted by cyj4369
,

환경변수 삭제


unset

Posted by cyj4369
,

## 리눅스 압축 명령어

* tar 

tar은 은밀히 말하면 압축방식이 아니다. 일종의 묶음 파일로 이해하는 것이 좋을듯 하다.
이 tar과 gzip을 같이 사용하는 경우 tar.gz (또는 tgz)라는 확장자를 사용하게 된다.
tar이 비록 묶음 파일이라 하더라도 여기서는 압축파일의 하나로 이해하고 이를 묶고 푸는
방법에 대해 알아보도록 한다.


- 압축 생성
  # tar cvf temp.tar temp/
    ; temp 디렉터리를 temp.tar 이라는 파일로 묶는다.

     (temp 디렉터리와 그 이하의 모든 파일 및 디렉터리)

 

- 압축 해제
  # tar xvf temp.tar

 

※ 옵션설명
  -c : (create) 압축 파일을 생성한다.
  -x : (extract) 압축 파일을 해제한다.
  -v : 압축파일이 생성(해제)되는 과정을 보여준다.
  -f : 압축파일 또는 Archive 장치를 사용한다.
  -t : 압축파일 내용 확인
  -r : 압축파일 추가
  -z : gzip으로 압축/해제
  -j : bzip2으로 압축/해제

※ tar 명령에서 옵션 앞에 붙는 "-" 기호는 붙여도 되고, 붙이지 않아도 된다.

※ gzip과 같이 압축된 파일의 경우 (tar.gz 또는 tgz) -z 옵션을 사용하여 한번에
   처리할 수 있다.
 

 

* gzip (tar.gz 또는 tgz)
 
앞서 보았던 tar로 묶여진 파일을 다시 압축하는 방법으로 많이 사용되는 압축형태이다.
gzip 명령으로 압축하고 gunzip 명령으로 압축을 해제한다.


- 압축 생성
  
  # gzip temp.tar
  
  위 명령을 사용하면 temp.tar.gz 이라는 파일이 생성된다.

 

- 압축 해제
 
  # gunzip temp.tar.gz
  
  
  # gzip -d temp.tar.gz


 

※ gzip 명령으로 압축을 해제하면, 그 전단계인 tar 묶음 형태로 압축이 풀리게 되므로
   tar 명령으로 다시한번 묶음을 해제해야 한다. 최근에는 이러한 번거로운 과정을
   줄이기 위해 tar 명령에서 tar 묶음 및 gzip 압축까지 모두 해제할 수 있는 옵션(-z)을
   제공한다.
  
  # tar xzvf temp.tar.gz
 

 

* bzip2 (bz2) 

gzip과 같이 최근 많이 사용되는 압축 형태로 tar.bz2 라는 확장자로 다루어진다.
역시 tar 묶음에 다시 압축을 가하는 형태이며, bzip2 전용 명령도 있으며, 
tar에서도 한번에 사용할 수 있는 옵션(-j)이 있다.

- 압축 생성
  # bzip2 -zkv temp.tar

- 압축 해제
  # bunzip2 temp.tar.bz2

※ bzip2 명령으로 압축을 해제하면, tar 명령을 다시 사용해야 하므로, 최근에는 tar에서
   바로 해제하는 경우가 많다.
  
  # tar xjvf temp.tar.bz2
 
* zip 

zip 파일은 Windows에서도 많이 사용되는 압축 형태로, 리눅스에서도 동일하게 사용할 수 있다.

- 압축 생성
  
  # zip -v temp.zip temp/*
   
    ; temp 디렉터리 이하의 모든 파일을 zip으로 압축한다.

- 압축 해제
  
  # unzip temp.zip
 
* compress

확장자 .Z 형태의 압축파일 생성

# compress    [파일명]     : 압축시 

# uncompress  [파일명]    : 해제시  

* zcat 명령어 

zcat -DVv [file...]

zcat 명령은 compress 명령 또는 mkszip 명령으로 압축된 data file을 input으로 취한다.
만약 data file이 command line에 적혀 있지 않는다면 standard input을 읽게 된다.
또한 standard input을 어떤 파일로 적으므로써 zcat에 보낼수 있다.

zcat은 모든 압축된 입력 파일의 압축을 풀어서, standard out에 적는다.
zcat은 cat이 하는 것과 동일한 concatenates을 한다.

압축된 inputfile의 이름은 .z, .gz, bz2로 끝날것을 예상한다.
특정 파일이름이 이런 첨자로 끝나지 않는다면, zcat은 file.z, file.gz, file.bz2로 끝나는
파일을 찾는다. 예를 들어 command line에 abc라는 파일이 적혀있다면,
zcat은 abc.z, abc.gz, abc.bz2를 찾는다. 만약에 이들 중 어느 것도 찾지 못한다면,
zcat은 abc를 확장자 없이 취급한다.

zcat은 다음과 똑같다.

uncompress -c

옵션

-D : compress나 mkszip의 directory option을 사용해서 압축된 파일을 압축해제하라.

-V : zcat의 version을 화면에 나타내라.

-v : 압축된 파일의 각각의 이름을 화면에 나타내라.

Posted by cyj4369
,

여러가지 이유로 MBR이 제거되는 경우가 있는데(저같은 경우는 윈도우와 리눅스를 같이 사용하다 윈도우를 재설치하여 MBR이 제거됨)
다음 단계를 거치면 MBR을 복구할 수 있다.

1단계 :   리눅스 설치 CD 1번(grub를 지원하는 어느  배포판이든 가능(?))을 가지고 복구 모드로 부팅을 한다. (전 우분투 6.10이 설치되어 있었는데 Fedora 6 시디를 사용)
boot: linux rescue

2단계 : 부팅을 한후 복구 모드로 들어가서 다음 명령어를 사용하여 실행한다.
 sh-3.1#: grub

3단계 :grub 실행후 grub shell에서 다음 명령어를 사용하여 실행한다.
grub> root (hd0,2)
Filesystem type is ext2fs, partition type 0x83

위 명령어를 실행하였을 경우 Filesystem ... 라고 나오면 성공한것이고 그렇지 않으면  
Filesystem type unknown, partition type 0x82  또는 Error 23: Error while parsing number 
메시지가 출력된다.

참고 :   위의 명령어중 hd0,2 라는 것이 있는데  이것은  사용자의 파티션에 따라서  모두 다릅니다.  따라서  사용자의 하드디스크의 수및 파티션수에 따라  입력을 하여야 합니다.
저는 하드디스크  하나(hd0)에 윈도우 파티션이 2개 그외 리눅스 파티션을 이용하고 있었습니다. 만약 2개 하드디스크를 사용하고 있는데 두번째 하드디스크에 리눅스를 설치하였다면  hd1 입니다.  하드디스크의 수는 0번부터 시작합니다. 
그리고 2라는 것은 /boot (만약 /boot 파티션을 별도로 잡지 않고 / 파티션에 설치하였을 경우는 / )가   설치되어 있는 파티션 번호입니다.  이것은 /dev/sda3에 설치되어 있었기 때문에 이 번호 또한 0번부터 시작하므로 2가 됩니다.

/dev/sda1 => 윈도우 C  드라이브
/dev/sda2  => 윈도우 D 드라이브
/dev/sda3 => 리눅스 /boot 
/dev/sda4 => 리눅스 /
/dev/sda5 => 리눅스 swap

4단계: MBR에 GRUB를 설치한다.(대부분의 경우 첫번째 하드디스크입니다.)
grub> setup (hd0)
Checking if "/boot/grub/stage1" exists ... no
Checking if "/grub/stage1" exists ... yes
Checing if "/grub/stage2" exists ... yes
Checking if "/grub/e2fs_stage1_5" exists ... yes
Running "embed /grub/e2fs_stage1_5 )hd0)" .. . 15 sectors are embedded.
Running "install /grub/stage1 (hd0) (hd0)1+15 p (hd0,2)/grub/stage2 /grub/grub.conf"... succeeded.
Done.

5단계: grub shell에서 빠져나오고 리부팅을 시켜준다.
grub>quit
sh-3.1# reboot ( 또는 ctrl + alt + del  키를 누른다.)

혹시라도 리부팅후 바로 부팅매니저가 나오지 않고 grub shell로 빠질경우 3,4단계를 다시한번 해준다. 그리고 리부팅하면 정상적으로 될 것이다.

참고사항 #1

grub 상태에서 윈도우로 부팅하려면 (C 드라이브에 윈도가 깔려있다고 할 경우) 다음 명령어를 실행하면 된다.

grub>root  (hd0,0)
grub>chainloader +1
grub>boot


grub 상태에서 리눅스를 부팅하려면

grub>root(hd0,2)  //여기서 2는 리눅스가 설치된 파티션을 말한다.

grub>kernel  /커널파일이름 ro root=/dev/sda3 ro  quiet  splash (Ubuntu)

grub>kernel  /커널파일이름 ro root=/dev/sda3 ro  rhgb  quiet  (RedHat 계열)

grub>boot

=>  커널파일이름 :  vmlinuz-2.6.x 와 같은 형식으로 되어 있다.  (/boot/grub/menu.lst 참고)
 
참고 사항 #2
윈도우와 리눅스를 같이 사용하다 리눅스를 삭제한후에 혹시라도 부팅할때 부트 매니저  lilo, grub 등이 남아 있을 경우는 아래 방법으로
하드 디스크(hard disk)의 MBR 영역을 초기화 해주면 된다.


첫번째 방법 : 응급복구 디스크를 이용하여(fdsik  파일포함) 도스(DOS)로 부팅해서 명령 프롬프트(command prompt)에서   fdisk /mbr  실행

두번째 방법 : 윈도xp CD로 부팅해서 복구 모드(recovery mode)로 들어간 후 명령 프롬프트(command prompt)에서   fixmbr 실행

'Embedded Lab > linux, x86' 카테고리의 다른 글

[환경변수 삭제]  (0) 2013.03.29
[리눅스 압축명령]  (0) 2013.03.28
[우분투에서 GRUB메뉴가 안보일 때]  (0) 2013.03.28
[에뮬레이터와 시뮬레이터의 차이]  (0) 2013.03.24
[어셈블리와 어셈블러]  (0) 2013.03.17
Posted by cyj4369
,

1.
/etc/default/grub 을 편집한다.


2.
GRUB_HIDDEN_TIMEOUT=0 를 주석처리한다.
(GRUB_TIMEOUT=10이라는 것은 10초후에 자동으로 부팅된다는것...)


3.
update-grub 을 때리고 재부팅.

Posted by cyj4369
,

게임 중에 시뮬레이션 게임들이 있죠.
그 시뮬레이션 게임들은 실제 상황을 시뮬레이션 해서 만드는 것입니다.
즉, 실제와 완전히 똑같을 필요까지는 없고 시뮬레이션하는 대상이 지니는 주요 특성만을 
재현해주면 되는 것입니다.
비행 시뮬레이션 이라면 하늘을 나는 것처럼 3D표현으로 화면에 보여주고
하늘을 나는 것처럼 조작할 수 있게 해주면 되는 것이죠.
물론 실험용 시뮬레이션이라면 바람이나 기후에 의한 영향이라던지
기체의 상태에 의한 영향 같이 더 자세한 특성들을 재현해줘야 하는 것이지만
그렇다고 해서 모든 것(화면 모습의 텍스쳐를 실제 현실처럼 자세하게 해줘야 한다거나 하는...)을
재현할 필요까지는 없습니다. 
심지어는 어떠한 시뮬레이션의 경우는 단순히 그 상황에 대한 관측 수치만 제공하는 경우도 있습니다.

그에 반해 에뮬레이터는 재현고자 하는 대상을 완벽하게 재현하는 것이 목표입니다.
어떠한 PDA를 에뮬레이션 하려고 한다면 PDA에 사용된 cpu가 처리할 수 있는 명령어들을
그대로 처리할 수 있는 가상의 cpu를 구현해야 하고 PDA에 사용된 디스플레이와 같은
해상도에서 PDA와 동일한 성능으로 PDA에서 돌아가는 프로그램을 사용할 수 있어야 합니다.
간단히 말하자면 에뮬레이터는 어떠한 하드웨어를 소프트웨어 적으로 재구현하는 것이죠.
(유사하게 하드웨어 -> 하드웨어는 짝퉁(카피) (중국의 짝퉁 자동차나 짝퉁 mp3같은... ) 
소프트웨어 -> 소프트웨어는 클론( 네이트온을 대신하는 Jateon 같은... )
소프트웨어 -> 하드웨어는 생각이 안나는군요. (이러는 경우가 있기는 하던가요;;)
이라고 할 수 있겠습니다. )

그리고 그 설명에서는

"시뮬레이터는 하드웨어도 포함할 수도 있지만
에뮬레이터는 소프트웨어적으로만 구현하는 것을 의미한다."

라고 이해하시면 될거 같습니다.
저 차이는 두가지를 완벽하게 구분하는데 사용하기는 힘든 특성이죠.

즉, 시뮬레이션은 소프트웨어적, 하드웨어적, 혹은 소프트웨어+하드웨어 등을 동시에 사용하여
어떠한 상황에 대한 자세한 데이터를 수집하거나 보여주는 것이 목적이고,

에뮬레이션은 어떠한 하드웨어를 소프트웨어적으로 구현하여 대상 하드웨어를 사용하는 것과
동일하게 사용하는 것이 목적이라고 할 수 있겠습니다.

============================================================

에뮬레이션은 진실값으로 대체 하는 거고, 시뮬레이션은 모델링 한 적절한 값으로 대체 하는 겁니다.
어떤 시스템을 모델링 한다는 것은 그 시스템과 100% 일치되지는 않지만 주요 특징을 살리는 결과물을 
만들어 내는 것입니다.따라서 "xxx 를 시뮬레이션 해보자" 하는 것은 xxx 의 주요 특징을 모델링 하고 (주로 수식으로)
거기에 입력을 가한 후 출력을 보는 것입니다.
에뮬레이션은 100% 동일해야 합니다. 현실에서 어려운 경우가 많죠.

과거에는 프로그래밍 할 때 에뮬레이터나 시뮬레이터를 사용했습니다.
가령 8086 이나 Z80 을 개발한다면 해당 에뮬레이터를 구입해서 (노트북 만하게 생겼습니다.)
개발중인 보드의 cpu 대신에 에뮬레이터 소켓을 꼽습니다.
그러면 이제 부터 에뮬레이터가 해당 cpu 를 대신 합니다.
에뮬레이터를 작업 pc 에 연결해서 작업합니다.
cpu 내부 실행되는 상황파악은 물론, 각 핀들을 물리적으로 컨트롤합니다. cpu 와 완전 동일한 거죠.

에뮬레이터가 비싸서 어려움이 있다면 시뮬레이터를 구입합니다. 이것은 소프트웨어의 일종입니다.
작업 pc 에서 소프트웨어를 구동하고 target cpu 를 프로그램적으로 하나 만들어 내서 
내가 작성한 코드를 실행해 주죠. 물리적인(전기적인) 동작은 할 수 없고,
프로그램의 논리관계만 검증합니다.

지금 주류가 된 ARM mcu 도 초기에는(2000년대 초반 ???) arm 에서 판매하는 500만원짜리 에뮬레이터를 
가지고 작업했습니다. 지금은 그거 없어도 무관한 것 같은데요....ㅎㅎㅎ.

Posted by cyj4369
,

[SWI의 진실]

Embedded Lab/ARM 2013. 3. 22. 19:53

Exception Handler를 다루다 보니, 궁금한 게 생겼어요. Hardware없이 interrupt를 거는 방법이 있을까요? SoftWare Interrupt라는 거 앞에서부터 언급되었었는데, Interrupt는 Asynchronous하게 암때나 걸리는 게 Interrupt일진데, Software로 어떻게 암때나 interrupt를 건다는 얘길까요. 실은 Software Interrupt라는 건 Interrupt가 아니에요. 실은 Software적으로 Exception을 걸 수 있는 걸 말하는 거죠. Software적으로 Exception을 걸게 되면 보통 User mode에 있던 System이 Supervisor mode로 전환이 되고요, Software Interrupt를 거는 순간부터는 Privileged Mode로 전환되는 거니까, System을 마음대로 주무를 수 있는 권한이 생기는 거죠. 
 
왜 이런 SWI를 굳이 사용하는 걸까요? compatibility때문에 사용하게 되는 경우가 많습니다. 보통은 kernel service를 이용할 때 많이 사용되는데요, 이렇게 하면 좋은 점이 말이죠, 일단은 Privileged mode로 들어갈 수 있게 되고, Kernel service로 들어서는 입구가 하나로 한정이 되므로 Kernel 입장에서는 SWI 부분만 수정을 잘하면 되는 장점이 있지요. 이런걸 유식한 말로 compatibility라고 합니다. 냐하하. 
 
SWI가 이용되는 대표적인 예는 아래의 두 가지에요. 
1. System Call (Kernel)
2. Semi hosting
 
System Call이 보통 Kernel등에서 많이 사용되는 개념인데, Kernel은 SVC mode에서 동작하고, 일반 application은 User Mode에서 동작하기 때문에, User Mode의 일반 application이 Kernel에게 service를 요청할 때 사용하지요. SWI를 걸어서 Kernel Mode로 System mode를 바꾸는 거죠 뭐. 
 
그리고, Semi hosting이라는 건 Target에서 I/O에 관련된 것들을 경로를 바꾸어 Target에서 실행되어야 하는 I/O를 Debugger를 실행하고 있는 Host system에서 대신 수행하게 하는 것인데, 예를 들면 UART로 Message를 뿌리던 target의 routine을 Semi hosting routine으로 갈아치우면, UART가 아닌 Debugger로 target의 Reporting을 직접 받을 수 있는 장점이 있어요. 이런 Semi hosting에 관련된 자세한 내용은 How to Debug section에서 다시 자세히 기술할 예정이오니, 여기서는 concept만 잘 가져가시도록 하시죠. 
 
그러면, SWI는 어떻게 구현되고, 어떻게 Handler를 구현하게 되는 걸까 하는 문제에 focusing을 해보는 게 어떨까 생각 중입니다. 
 
Software Interrupt를 걸려면 어떻게 해야 할까요? 간단하죠. 
SWI {condition}
이렇게 assembly를 삽입해 주면 SWI 명령어를 만나는 순간 Exception은 발생하고, SWI Exception Vector (0x0008)번지로 branch하게 됩니다. 이렇게 SWI 명령어 자체로 Exception을 걸어 User mode에서 강제로 SVC mode로 갈 수 있다니 이 얼마나 시적인 일입니꺄.
 
SWI {condition} 이라고 했는데, 그러면 SWI에 대해서 여러 가지 종류의 SWI를 걸 수 있다는 말인데요, 즉 슨 SWI 뒤에 숫자를 적어 넣고, 막상 Handler에서 뒤에 parameter로 준 condition을 switch 걸어서 여러 가지 case를 처리할 수 있다는 말이기도 하지요. 
 
그런데, ARM에서는 Exception이 발생하고 나면, Exception Vector로 jump해서 곧바로 Handler로 branch한다고 보았었는데, 어떻게 parameter를 준다는 말입니까. 이거야 말로 귀신이 곡할 노릇노릇 노른자이네요. 이것이야 말로 System Software를 하는 사람들의 실력이 빛을 발하는 순간이에요. 
 
모든 것은 원하는 것이 있으면 통하는 법이죠. 그것의 비밀은 SWI 명령자체가 비밀입니다. SWI 명령어의 32bit binary 형태를 한번 볼까요?
 
 
 
32bit 명령어 중 MSB 4bit는 조건을 나타내는 명령어, 즉 EQ, NEQ 등의 뭐 그거 있었잖아요. condition flag를 보고서 어떻게 할거냐는 조건 명령 그게 4bit 들어가고요. 바로 다음에 따라오는 4bit에 연달아 1111이 있으며 SWI 명령입니다. 그러면, 뒤에 24bit가 남게 되죠. 이 24bit에 해당하는 곳에 parameter가 들어갈 수 있게 되는 거죠. 실은 버려지게 되는 내용이지만, 재활용 수준에서 이걸 가져다가 여러 가지 종류의 SWI를 거는 것처럼 만들 수 있어요. 순수하게 System Software Engineer가 구현해야 하는 몫이에요. 뒤에 붙어 있는 LSB 24bit와는 아무 상관없이 일단 1111 (SWI)가 있으면 Processor는 Exception을 발생시킵니다. 그러면, 뒤에 붙어 있던 LSB 24 bit를 어떻게 parameter로 재활용할 수 있을 까요. 자자, 생각해 봅시다. 힌트는 Software Interrupt가 걸리게 되면, R14_SVC에 돌아갈 주소가 저장된다는 사실이에요. 
 
으흐흐, 그렇죠. 돌아갈 주소를 안다는 것은 돌아갈 주소에서 한 칸만 이전을 가져올 수만 있다면 SWI가 걸린 위치를 가져올 수 있다는 말이지요. 그러면 SWI가 걸린 위치를 가져와서 LSB 24bit만 Masking해내면 요리 끝이에요. 뭐 다 이런 식인 거에요. 
 
LDR r0, [r14, #-4]
BIC r0, r0, #0xFF000000 
 
요렇게 하면 r14가 가리키는 곳에서 4를 뺀 곳의 값 자체를 읽어와서 하위 24 bit를 r0에 긁어 올 수 있겠어요. 짜란! 자자, 그러면 실제로 어떻게 Software를 짜는지 알아야 하지 않겠어요?
 
두 가지 예를 들어볼 게요.하나는 위에서 본 것과 같은 SWI 호출과 Handler의 구현입니다. 나머지 한가지는 C Level의 SWI 의 직접 호출 구현이지요. 궁금 안 하실지도 모르겠으나, 조금 살펴 보져 머. 
 
첫 번째, 일반적인 SWI 호출하는 방법을 한번 해보시지요. 
 일단 c file에서 SWI를 호출해야겠죠. SWI_OOOPS()라는 함수에서 SWI 호출해 보겠습니다.
 
 
SWI_OOOPS()
{
    .............
    SWI_Exception();
    .............
}
 
그러면, SWI Assembly 명령어를 사용하기 위하여, Assembly file 하나에서 SWI_Exception 함수를 구현해 볼까요. 아래처럼 직접 SWI에 parameter 0x121212를 줘봅시다. 
 
SWI_Exception
  SWI  0x121212
이렇게 하면   SWI  0x121212 를 만나는 순간 곧바로 Software Interrupt가 걸리게 되고 Exception Vector로 branch하게 됩니다. 
 
0x8번지에 이렇게 씌여져 있겠죠. 
b SWI_Handler
 
그러면, 이제 간단하게 C Level의 SWI Handler를 부르기 위한 Handler를 만들어 주면 됩니다. 물론 여기에서 LSB 24 bit도 건져 내야죠.
 
 
SWI_Handler
   STMFD sp!, {lr}                  ; 돌아갈 주소 저장
   LDR  r0,  [lr, #-4]                  ; SWI 주소의 값을 가져옴. 
   BIC  r0,  r0,  #0xFF000000      ; LSB 24bit 건져냄. 
   BL  SWI_C_Handler                 ; r0에 넣었으니까, AAPCS에 의하여 첫번째 argument로
   LDMFD sp!, {lr}                     ; 다 처리하고 왔으면 돌아가야지~

 

뭐 이런 Story죠.

그럼 이때! SWI_C_Handler에 잘 도달 할 수 있도록 수로를 잘 터왔으니까, SWI_C_Handler만 잘 구현하면 됩니다. 잘 보세요.

 

 

void SWI_C_Handler (int OPTion)

 
 switch(option)
 {
  case 0x123432: 
           UART_MESSAGE ("SWI 0x123432");
      break ;
  case 0x121212 :
           LCD_MESSAGE ("SWI 0x121212");
      break ;
  case 0x654321:
           USB_MESSAGE ("SWI 0x654321");
      break ;
 }
 
}
 
r0에 LSB 24 bit를 넣었으니까, 그 값은 int option으로 넘어오게 되고, 그 option에 대해서 switch를 걸었으니까 결국 LCD_MESSAGE 를 찍겠네요. 음.. 어렵지 않군요. 
 
자, 여기서 그럼 다른 종류의 LSB 24bit를 걸기 위해서 SWI_Exception() 함수를 Assembly로 따로따로 구현해야 하느냐! 조금 더 편한 방법이 있어요. 
 
함수를 SWI와 번호로 선언할 수 있어요.

 
 __swi(0x123432) void UART_OUT (void)라고 선언하고서,
 
SWI_OOOPS()
{
    .............
    SWI_Exception();
    UART_OUT();
    .............
}
 
이렇게 부르면 차례로 LCD MESSAGE와 UART MESSAGE가 실행되게 됩니다. 어떻게 해서 이런 일이 가능한 것이냐 하면, UART_OUT() 함수 자체가 SWI 0x123432으로 compile 된답니다.
결국 SWI_OOOPS()함수는
 
 
SWI_OOOPS
   ........
   SWI 0x121212
   SWI 0x123432
   .........
 
이런 식으로 컴파일 되겠죠 뭐.

출처 : http://recipes.egloos.com/5037342

'Embedded Lab > ARM' 카테고리의 다른 글

[STM32 : SPI, using chip select2]  (0) 2014.03.05
[STM32 : SPI, using chip select]  (0) 2014.03.05
[논리 스프트와 산술 시프트의 차이]  (0) 2013.03.20
Posted by cyj4369
,

논리 시프트와 산술 시프트의 차이

논리 시프트 역시 비트를 이동하는 연산이나, 산술 시프트와의 제일 큰 차이는 부호비트(sign bit)가 보존되지 않는다는 것이다. 따라서 부호가 정의된 16비트 정수(signed integer)에서 연산의 결과값이100 0000(2)=32768(10) 이상의 범위를 넘어갈 경우 부호가 바뀌는 경우가 발생한다.    

'Embedded Lab > ARM' 카테고리의 다른 글

[STM32 : SPI, using chip select2]  (0) 2014.03.05
[STM32 : SPI, using chip select]  (0) 2014.03.05
[SWI의 진실]  (0) 2013.03.22
Posted by cyj4369
,

MASM(Microsoft Macro Assembler), NASM(Netwide Assembler), FASM(Flat Assembler), GAS(GNU Assembler), YASM 등 정말 다양한 종류가 있습니다. 그럼 여기서 잠시 질문하나 드리겠습니다. 어셈블리(Assembly)는 무엇이고 어셈블러(Assembler)는 무엇일까요? 그렇습니다. 어셈블리는 언어를 말하는 것이고, 어셈블러는 compiler 를 의미하는 것입니다. 물론 어셈에서는 C언어처럼 컴파일 이라는 용어대신 Assemble 한다고 표현하며, 이 동작을 해 주는 녀석을 Assembler 라고 말합니다.

 자, 그럼 위에서 나열한 것은 Assembler 의 종류입니다. 그런데 왜 각각에 대해서 문법이 다를까요?
Assembler 마다 지원하는 platform 이 다르고, syntax 형태도 차이가 있습니다. 당연히 platform 에 따라 종류를 나누면 상당히 많은 어셈블리가 존재하지요. 인텔(Intel)의 IA-32 Assembly 도 있고, IA-64 Assembly 도 있습니다. 그 이외에 상당히 많은 종류의 어셈블리(Assembly)가 존재하지요. syntax 에는 Intel 방식과 AT&T 방식이 있습니다. 자세한 내용은 아래에서 계속 설명 드리도록 하겠습니다.


GAS(GNU Assembler)

GAS 는 약자 속에 나와 있듯이 GNU Project 에서 사용되고 만들어진 어셈블러입니다. 당연히 GCC 안에 기본적으로 사용되는 녀석이기도 하지요. Linux 에서 인라인 어셈을 해 보신 분은 GAS가 어떤 syntax 를 사용하는지 아실겁니다. 바로 AT&T 입니다. 제가 싫어하는 문법이기도 하지요 =_=; 간단히 예를 들면 MOV EAX, 80 을 MOV $80, %EAX 로 표현합니다. 전자는 AT&T 이외에 다른 syntax 인 Intel syntax 입니다. 여튼 GAS는 Free Software 이고, Cross Platform 을 지원합니다.


MASM(Microsoft Macro Assembler)

가 장 많이 들어보셨을 어셈블러(Assemler)라고 생각합니다. Microsoft 에서 만들었으며, 많은 사랑을 받아온 어셈블러입니다. 64-bit 도 지원하며, syntax 는 Intel 방식을 따릅니다. 개인적으로 저는 이 syntax 가 가독성이 좋습니다. MASM 는 초기에 유료로 제공되었으며 사용하기 위해서는 별도로 설치를 해 주어야 합니다. 하지만 이제는 뮤로로 제공되며 고맙게도 Visual Studio 2008 이상 버젼부터는 기본적으로 MASM v9.0이 기본적으로 포함되어 있기 때문에 별도 설치를 해 줄 필요가 없습니다. 더불어 MASM 은 이름에서도 알 수 있듯이, 강력한 Macro 를 지원해줌으로써 프로그래머가 좀 더 편리하게 개발 할 수 있도록 지원해 줍니다. 편리하긴 하지만 때론 Assemly 의 참 모습을 잃어가는 것 같아 조금 아쉽기도 하네요. 참, 아시다시피 cross-platform 은 지원되지 않습니다 ^-^;

참고 사이트
http://www.masm32.com
http://www.movsd.com


NASM(Netwide Assembler)

80x86 platform 용으로 개발된 어셈블러입니다. 그리고 open-source 로 시작되었지요. 왜 그랬을까요? 네, 바로 Microsoft 때문입니다 -_-; 당시 Microsoft 의 MASM은 상용으로서 돈을 지불하고 사야만 했기 때문이죠. 그렇기에 MASM과 비슷한 점이 많고, 사람들의 비교 대상도 되곤 합니다. NASM의 장점은 현재는 Cross-Platform 을 지원한다는 것과 Macro(단, x86 platform에서) 를 제공한다는 것입니다. 그렇기에 일반적으로 Kernel 과 같이 O/S를 개발할 경우에 많이 사용되는 Assembler 입니다.

참고 사이트
http://www.nasm.us



이외의 Aseembler

이밖에 어셈블러(Assembler)는 다음 주소를 참고하시기 바랍니다.
JWASM : http://www.japheth.de/JWasm.html
FASM : http://flatassembler.net/
YASM : http://www.tortall.net/projects/yasm/




출처 http://rootfriend.tistory.com/entry/어셈블러Assembler의-종류

Posted by cyj4369
,