Now supports cpio format too

This commit is contained in:
bzt 2018-01-18 14:00:39 +01:00
parent a5cbe88e56
commit 12f9635933
6 changed files with 131 additions and 45 deletions

View File

@ -35,13 +35,18 @@ start.o: start.S
%.o: %.c
aarch64-elf-gcc $(CFLAGS) -c $< -o $@
tar.o:
tar -cf initrd.tar *.md *.c *.h
aarch64-elf-ld -r -b binary -o tar.o initrd.tar
tar:
tar -cf ramdisk *.md *.c *.h
kernel8.img: start.o tar.o $(OBJS)
aarch64-elf-ld -nostdlib -nostartfiles start.o tar.o $(OBJS) -T link.ld -o kernel8.elf
cpio:
ls *.md *.c *.h | cpio -H hpodc -o >ramdisk
rd.o: ramdisk
aarch64-elf-ld -r -b binary -o rd.o ramdisk
kernel8.img: start.o rd.o $(OBJS)
aarch64-elf-ld -nostdlib -nostartfiles start.o rd.o $(OBJS) -T link.ld -o kernel8.elf
aarch64-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
rm kernel8.elf *.o *.tar >/dev/null 2>/dev/null || true
rm kernel8.elf *.o >/dev/null 2>/dev/null || true

View File

@ -5,9 +5,14 @@ Sok OS használ kezdeti memória lemezt (initrd) hogy fájlokat töltsön be ind
ilyen oktatóanyagnak, mivel a legtöbb hobby OS fejlesztőnek fingja sincs, hogy kell ezt rendesen csinálni.
Először is, nem fogjuk újra feltalálni a spanyol viaszt és kiagyalni egy új formátumot, amihez aztán egy
szörnyű kreátor programot heggesztünk. Helyette a POSIX szabvány `tar` archíválót fogjuk használni. A formátuma
pofonegyszerű, először jön egy 512 bájtos fejléc a fájl adataival, majd ezt követi a fájl tartalma nullákkal
kiegészítve, hogy a hossza 512-vel osztható legyen. Ez ismétlődik minden egyes fájlra az archívban.
szörnyű kreátor programot heggesztünk. Helyette a POSIX szabvány `tar` archíválót és a `cpio` parancsot
fogjuk használni. Előbbi egyértelműbb, utúbbit a Linux is használja.
A tar formátuma pofonegyszerű, először jön egy 512 bájtos fejléc a fájl adataival, majd ezt követi a fájl
tartalma nullákkal kiegészítve, hogy a hossza 512-vel osztható legyen. Ez ismétlődik minden egyes fájlra az archívban.
A cpio nagyon hasonló, csak változó hosszúságú fejléccel operál, és nincs a fájl tartalma kiegészítve.
Ha szeretnél tömörített initrd-t, akkor javaslom például a [tinf](https://bitbucket.org/jibsen/tinf) könyvtárat
a kicsomagoláshoz. A kitömörített adatot az itt ismertetett módszerrel olvashatod.
@ -23,25 +28,31 @@ nem kell SD kártya olvasó és FAT értelmező, így a kerneled jóval kissebb
[config.txt](https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md) parancsait illeti,
két lehetőséged is van:
`initramfs (fájlnév) followkernel` - ez betölti a (fájlnév) nevű fájlt mindjárt a kerneled után. Az initrd-d kezdőcíme
`ramfsfile=(fájlnév)` - ez betölti a (fájlnév) nevű fájlt mindjárt a kerneled után. Az initrd-d kezdőcíme
ekkor a *&_end* cimke lesz, amit a linker szkriptben definiáltunk.
`initramfs (fájlnév) (cím)` - a megadott címre tölti be a (fájlnév) nevű fájlt. A kezdőcíme ekkor *(cím)* lesz.
### Statikus linkelés
Nem túl praktikus, mivel mindig újra kell fordítani a kernelt, ha változtatni akarsz az initrd tartalmán. Azonban
ez a legegyszerűbb módszer, és hogy átlátható legyen az oktatóanyag, ezért ezt választottam. Az initrd-d kezdőcímét
ez esetben a *_binary_initrd_tar_start* cimke szolgáltatja.
ez a legegyszerűbb módszer, és hogy átlátható legyen az oktatóanyag, ezért ezt választottam. Az initrd-d
kezdőcímét ez esetben a *_binary_ramdisk_start* cimke szolgáltatja.
Makefile
--------
Hozzáadtam egy tar.o létrehozó szabályt a Makefile-hoz. Ez dinamikusan legenerálja a tar-t, majd object fájllá
konvertálja.
Hozzáadtam egy rd.o-t létrehozó szabályt, ami object fájllá konvertálja az archívot. Ezen kívül lett két
új szabály:
`make tar` ami *tar* formátumban hozza létre az archívumot
`make cpio` ami pedig *cpio hpodc* formátumot használ.
Ezért amikor fordítani szeretnél, vagy a `make tar all`, vagy a `make cpio all` parancsot kell használnod.
Initrd.h, initrd.c
------------------
`initrd_list(buf)` kilistázza a bufferben lévő tar archív tartalmát.
`initrd_list(buf)` kilistázza a bufferben lévő archív tartalmát. A formátumát automatikusan detektálja.
Main
----

View File

@ -5,13 +5,18 @@ Many OS uses initial ramdisk to load files into memory during boot. I felt the n
a tutorial as most hobby OS developer's never learned how to do this properly.
First of all, we're not going to reinvent the wheel a come up with a new format and an awful
image creator tool. We're going to use the POSIX standard `tar` utility to create our initrd. It's format
is really simple, first comes an 512 bytes long header with file meta information, followed by the
file contents padded with zeros to round up to multiple of 512 bytes. This repeats for every file in the archive.
If you want a compressed initrd, you can use for example the [tinf](https://bitbucket.org/jibsen/tinf) library to
deflate. The uncompressed buffer can be parsed by the method described here.
image creator tool. We're going to use the POSIX standard `tar` utility and the `cpio` utility
to create our initrd. The former is more straightforward, the latter is used by Linux.
Second, about loading it into memory, we have several options:
Tar's format is really simple, first comes an 512 bytes long header with file meta information, followed by the
file contents padded with zeros to round up to be multiple of 512 bytes. This repeats for every file in the archive.
Cpio is very similar but it has a variable length header and file content is not padded.
If you want a compressed initrd, you can use for example the [tinf](https://bitbucket.org/jibsen/tinf) library to
inflate. The uncompressed buffer can be parsed by the method described here.
Second, about loading your ramdisk into memory, we have several options:
### Load a file on our own
You can use the `fat_readfile()` from the previous tutorial. In that case your initrd's address
@ -23,27 +28,32 @@ any SD card reader or FAT parser at all, resulting in a much smaller kernel. As
[config.txt](https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md),
you have two options:
`initramfs (filename) followkernel` - this will load (filename) after your kernel. You can access it at the label
`ramfsfile=(filename)` - this will load (filename) after your kernel. You can access it at the label
*&_end* defined by our linker script.
`initramfs (filename) (address)` - load (filename) into a specified location. You can access it at *(address)*.
### Statically link
This is not very practical because you have to build your kernel every time you want to change the initrd. But
it is the simplest method, and to keep this tutorial simple we'll use this. You can access the initrd by the label
*_binary_initrd_tar_start*.
it is the simplest method, and to keep this tutorial simple we'll use this method. You can access the initrd by
the label *_binary_ramdisk_start*.
Makefile
--------
I've added a tar.o to the usual Makefile. This rule will dinamically create a tar file and convert it into an
object file.
I've added an rd.o rule to convert the archive into an object file. I've also added
`make tar` which will create an archive in *tar* format
`make cpio` which will create a *cpio hpodc* archive.
So when you compile, you either have to use `make tar all` or `make cpio all`.
Initrd.h, initrd.c
------------------
`initrd_list(buf)` list the contents of a tar archive in the buffer.
`initrd_list(buf)` list the contents of an archive in the buffer. Detects the format automatically.
Main
----
We initialize console and the pass the initrd buffer to lister.
We initialize console and then pass the initrd buffer to lister.

View File

@ -25,6 +25,41 @@
#include "uart.h"
/* POSIX ustar header format */
typedef struct { /* byte offset */
char name[100]; /* 0 */
char mode[8]; /* 100 */
char uid[8]; /* 108 */
char gid[8]; /* 116 */
char size[12]; /* 124 */
char mtime[12]; /* 136 */
char chksum[8]; /* 148 */
char typeflag; /* 156 */
char linkname[100]; /* 157 */
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */
char gname[32]; /* 297 */
char devmajor[8]; /* 329 */
char devminor[8]; /* 337 */
char prefix[167]; /* 345 */
} __attribute__((packed)) tar_t;
/* cpio hpodc format */
typedef struct {
char magic[6]; /* Magic header '070707'. */
char dev[6]; /* device number. */
char ino[6]; /* "i-node" number. */
char mode[6]; /* Permisions. */
char uid[6]; /* User ID. */
char gid[6]; /* Group ID. */
char nlink[6]; /* Number of hard links. */
char rdev[6]; /* device major/minor number. */
char mtime[11]; /* Modification time. */
char namesize[6]; /* Length of filename in bytes. */
char filesize[11]; /* File size. */
} __attribute__((packed)) cpio_t;
/**
* Helper function to convert ASCII octal number into binary
* s string
@ -41,36 +76,61 @@ int oct2bin(char *s, int n)
}
/**
* List the contents of a tar archive
* List the contents of an archive
*/
void initrd_list(char *buf)
{
char *types[]={"regular", "link ", "symlnk", "chrdev", "blkdev", "dircty", "fifo ", "??? "};
uart_puts("Type Offset Size Access rights\tFilename\n");
uart_puts("Type Offset Size Access rights\tFilename\n");
// iterate on archive's contents
while(!__builtin_memcmp(buf+257,"ustar",5)){
int fs=oct2bin(buf+0x7c,11);
while(!__builtin_memcmp(buf+257,"ustar",5)) {
// if it's an ustar archive
tar_t *header=(tar_t*)buf;
int fs=oct2bin(header->size,11);
// print out meta information
uart_puts(types[buf[0x9c]-'0']);
uart_puts(types[header->typeflag-'0']);
uart_send(' ');
uart_hex((unsigned int)((unsigned long)buf)+512);
uart_send(' ');
uart_hex(fs); // file size in hex
uart_hex((unsigned int)((unsigned long)buf)+sizeof(tar_t));
uart_send(' ');
uart_puts(buf+0x64); // access bits in octal
uart_hex(fs); // file size in hex
uart_send(' ');
uart_puts(buf+0x109); // owner
uart_puts(header->mode); // access bits in octal
uart_send(' ');
uart_puts(header->uname); // owner
uart_send('.');
uart_puts(buf+0x129); // group
uart_puts(header->gname); // group
uart_send('\t');
uart_puts(buf); // filename
if(buf[0x9c]=='2') {
uart_puts(" -> "); // symlink target
uart_puts(buf+0x9d);
uart_puts(buf); // filename
if(header->typeflag=='2') {
uart_puts(" -> "); // symlink target
uart_puts(header->linkname);
}
uart_puts("\n");
// jump to the next file
buf+=(((fs+511)/512)+1)*512;
}
// if it's a cpio archive. Cpio also has a trailer entry
while(!__builtin_memcmp(buf,"070707",6) && __builtin_memcmp(buf+sizeof(cpio_t),"TRAILER!!",9)) {
cpio_t *header = (cpio_t*)buf;
int ns=oct2bin(header->namesize,6);
int fs=oct2bin(header->filesize,11);
// print out meta information
uart_hex(oct2bin(header->mode,6)); // mode (access rights + type)
uart_send(' ');
uart_hex((unsigned int)((unsigned long)buf)+sizeof(cpio_t)+ns);
uart_send(' ');
uart_hex(fs); // file size in hex
uart_send(' ');
uart_hex(oct2bin(header->uid,6)); // user id in hex
uart_send('.');
uart_hex(oct2bin(header->gid,6)); // group id in hex
uart_send('\t');
uart_puts(buf+sizeof(cpio_t)); // filename
uart_puts("\n");
// jump to the next file
buf+=(sizeof(cpio_t)+ns+fs);
}
}

Binary file not shown.

View File

@ -26,8 +26,8 @@
#include "uart.h"
#include "initrd.h"
// import our bitchunk from tar.o
extern volatile unsigned char _binary_initrd_tar_start;
// import our bitchunk from rd.o
extern volatile unsigned char _binary_ramdisk_start;
void main()
{
@ -35,7 +35,7 @@ void main()
uart_init();
// list contents of an archive
initrd_list((char*)&_binary_initrd_tar_start);
initrd_list((char*)&_binary_ramdisk_start);
// echo everything back
while(1) {