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 %.o: %.c
aarch64-elf-gcc $(CFLAGS) -c $< -o $@ aarch64-elf-gcc $(CFLAGS) -c $< -o $@
tar.o: tar:
tar -cf initrd.tar *.md *.c *.h tar -cf ramdisk *.md *.c *.h
aarch64-elf-ld -r -b binary -o tar.o initrd.tar
kernel8.img: start.o tar.o $(OBJS) cpio:
aarch64-elf-ld -nostdlib -nostartfiles start.o tar.o $(OBJS) -T link.ld -o kernel8.elf 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 aarch64-elf-objcopy -O binary kernel8.elf kernel8.img
clean: 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. 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 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 szörnyű kreátor programot heggesztünk. Helyette a POSIX szabvány `tar` archíválót és a `cpio` parancsot
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 fogjuk használni. Előbbi egyértelműbb, utúbbit a Linux is használja.
kiegészítve, hogy a hossza 512-vel osztható legyen. Ez ismétlődik minden egyes fájlra az archívban.
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 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. 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, [config.txt](https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md) parancsait illeti,
két lehetőséged is van: 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. 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. `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 ### Statikus linkelés
Nem túl praktikus, mivel mindig újra kell fordítani a kernelt, ha változtatni akarsz az initrd tartalmán. Azonban 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 a legegyszerűbb módszer, és hogy átlátható legyen az oktatóanyag, ezért ezt választottam. Az initrd-d
ez esetben a *_binary_initrd_tar_start* cimke szolgáltatja. kezdőcímét ez esetben a *_binary_ramdisk_start* cimke szolgáltatja.
Makefile Makefile
-------- --------
Hozzáadtam egy tar.o létrehozó szabályt a Makefile-hoz. Ez dinamikusan legenerálja a tar-t, majd object fájllá 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
konvertálja. ú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.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 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. 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 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 image creator tool. We're going to use the POSIX standard `tar` utility and the `cpio` utility
is really simple, first comes an 512 bytes long header with file meta information, followed by the to create our initrd. The former is more straightforward, the latter is used by Linux.
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.
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 ### Load a file on our own
You can use the `fat_readfile()` from the previous tutorial. In that case your initrd's address 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), [config.txt](https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md),
you have two options: 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. *&_end* defined by our linker script.
`initramfs (filename) (address)` - load (filename) into a specified location. You can access it at *(address)*. `initramfs (filename) (address)` - load (filename) into a specified location. You can access it at *(address)*.
### Statically link ### Statically link
This is not very practical because you have to build your kernel every time you want to change the initrd. But 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 it is the simplest method, and to keep this tutorial simple we'll use this method. You can access the initrd by
*_binary_initrd_tar_start*. the label *_binary_ramdisk_start*.
Makefile Makefile
-------- --------
I've added a tar.o to the usual Makefile. This rule will dinamically create a tar file and convert it into an I've added an rd.o rule to convert the archive into an object file. I've also added
object file.
`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.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 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" #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 * Helper function to convert ASCII octal number into binary
* s string * 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) void initrd_list(char *buf)
{ {
char *types[]={"regular", "link ", "symlnk", "chrdev", "blkdev", "dircty", "fifo ", "??? "}; 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 // iterate on archive's contents
while(!__builtin_memcmp(buf+257,"ustar",5)){ while(!__builtin_memcmp(buf+257,"ustar",5)) {
int fs=oct2bin(buf+0x7c,11); // if it's an ustar archive
tar_t *header=(tar_t*)buf;
int fs=oct2bin(header->size,11);
// print out meta information // print out meta information
uart_puts(types[buf[0x9c]-'0']); uart_puts(types[header->typeflag-'0']);
uart_send(' '); uart_send(' ');
uart_hex((unsigned int)((unsigned long)buf)+512); uart_send(' ');
uart_hex((unsigned int)((unsigned long)buf)+sizeof(tar_t));
uart_send(' '); uart_send(' ');
uart_hex(fs); // file size in hex uart_hex(fs); // file size in hex
uart_send(' '); uart_send(' ');
uart_puts(buf+0x64); // access bits in octal uart_puts(header->mode); // access bits in octal
uart_send(' '); uart_send(' ');
uart_puts(buf+0x109); // owner uart_puts(header->uname); // owner
uart_send('.'); uart_send('.');
uart_puts(buf+0x129); // group uart_puts(header->gname); // group
uart_send('\t'); uart_send('\t');
uart_puts(buf); // filename uart_puts(buf); // filename
if(buf[0x9c]=='2') { if(header->typeflag=='2') {
uart_puts(" -> "); // symlink target uart_puts(" -> "); // symlink target
uart_puts(buf+0x9d); uart_puts(header->linkname);
} }
uart_puts("\n"); uart_puts("\n");
// jump to the next file // jump to the next file
buf+=(((fs+511)/512)+1)*512; 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 "uart.h"
#include "initrd.h" #include "initrd.h"
// import our bitchunk from tar.o // import our bitchunk from rd.o
extern volatile unsigned char _binary_initrd_tar_start; extern volatile unsigned char _binary_ramdisk_start;
void main() void main()
{ {
@ -35,7 +35,7 @@ void main()
uart_init(); uart_init();
// list contents of an archive // list contents of an archive
initrd_list((char*)&_binary_initrd_tar_start); initrd_list((char*)&_binary_ramdisk_start);
// echo everything back // echo everything back
while(1) { while(1) {